From 8a69c0555bf38f20987a635827efc45eb5d42bf1 Mon Sep 17 00:00:00 2001 From: PrinsFrank <25006490+PrinsFrank@users.noreply.github.com> Date: Tue, 6 Feb 2024 12:57:34 +0100 Subject: [PATCH 01/40] Update plugin documentation (#11813) --- doc/articles/plugins.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/articles/plugins.md b/doc/articles/plugins.md index 019ab5d450ea..6c729a4e0a37 100644 --- a/doc/articles/plugins.md +++ b/doc/articles/plugins.md @@ -271,6 +271,8 @@ class Command extends BaseCommand protected function execute(InputInterface $input, OutputInterface $output): int { $output->writeln('Executing'); + + return 0; } } ``` @@ -285,7 +287,7 @@ Plugins for an event can be run manually by the `run-script` command. This works [running scripts manually](scripts.md#running-scripts-manually). If it is another type of plugin the best way to test it is probably using a [path repository](../05-repositories.md#path) -to require the plugin in a test project, and then `rm -rf vendor && composer update` +to require the plugin in a test project. If you are developing locally and want to test frequently, you can make sure the path repository uses symlinks, as changes are updated immediately. Otherwise, you'll have to run `rm -rf vendor && composer update` every time you want to install/run it again. ## Using Plugins From 0f70c0a9c91b61c4b2ad7bb4f6e92ddf715bc273 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 6 Feb 2024 12:57:52 +0100 Subject: [PATCH 02/40] Add detection of constraints which do not match anything in validate command, fixes #11802 (#11829) --- .../Package/Loader/ValidatingArrayLoader.php | 7 +++++++ .../Package/Loader/ValidatingArrayLoaderTest.php | 14 ++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/Composer/Package/Loader/ValidatingArrayLoader.php b/src/Composer/Package/Loader/ValidatingArrayLoader.php index dc50a84d0771..9f25ed2197f2 100644 --- a/src/Composer/Package/Loader/ValidatingArrayLoader.php +++ b/src/Composer/Package/Loader/ValidatingArrayLoader.php @@ -17,6 +17,8 @@ use Composer\Semver\Constraint\Constraint; use Composer\Package\Version\VersionParser; use Composer\Repository\PlatformRepository; +use Composer\Semver\Constraint\MatchNoneConstraint; +use Composer\Semver\Intervals; use Composer\Spdx\SpdxLicenses; /** @@ -290,6 +292,11 @@ public function load(array $config, string $class = 'Composer\Package\CompletePa ) { $this->warnings[] = $linkType.'.'.$package.' : exact version constraints ('.$constraint.') should be avoided if the package follows semantic versioning'; } + + $compacted = Intervals::compactConstraint($linkConstraint); + if ($compacted instanceof MatchNoneConstraint) { + $this->warnings[] = $linkType.'.'.$package.' : this version constraint cannot possibly match anything ('.$constraint.')'; + } } if ($linkType === 'conflict' && isset($this->config['replace']) && $keys = array_intersect_key($this->config['replace'], $this->config['conflict'])) { diff --git a/tests/Composer/Test/Package/Loader/ValidatingArrayLoaderTest.php b/tests/Composer/Test/Package/Loader/ValidatingArrayLoaderTest.php index 43a4749972d0..bcd029733633 100644 --- a/tests/Composer/Test/Package/Loader/ValidatingArrayLoaderTest.php +++ b/tests/Composer/Test/Package/Loader/ValidatingArrayLoaderTest.php @@ -480,6 +480,20 @@ public static function warningProvider(): array ], false, ], + [ + [ + 'name' => 'foo/bar', + 'require' => [ + 'foo/baz' => '>1, <0.5', + 'bar/baz' => 'dev-main, >0.5', + ], + ], + [ + 'require.foo/baz : this version constraint cannot possibly match anything (>1, <0.5)', + 'require.bar/baz : this version constraint cannot possibly match anything (dev-main, >0.5)', + ], + false, + ], [ [ 'name' => 'foo/bar', From bff129f4f57733298d97de6ac242b4b67c571eda Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 6 Feb 2024 13:27:55 +0100 Subject: [PATCH 03/40] Update require docs, fixes #11823 --- doc/03-cli.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/doc/03-cli.md b/doc/03-cli.md index 6e6809a49658..00734f605a2a 100644 --- a/doc/03-cli.md +++ b/doc/03-cli.md @@ -242,6 +242,9 @@ Specifying one of the words `mirrors`, `lock`, or `nothing` as an argument has t The `require` command adds new packages to the `composer.json` file from the current directory. If no file exists one will be created on the fly. +If you do not specify a package, Composer will prompt you to search for a package, and given +results, provide a list of matches to require. + ```shell php composer.phar require ``` @@ -256,7 +259,14 @@ to the command. php composer.phar require "vendor/package:2.*" vendor/package2:dev-master ``` -If you do not specify a package, Composer will prompt you to search for a package, and given results, provide a list of matches to require. +If you do not specify a version constraint, composer will choose a suitable one based +on the available package versions. + +```shell +php composer.phar require vendor/package vendor/package2 +``` + +If you do not want to install the new dependencies immediately you can call it with --no-update ### Options From ef6c224ec2191eaaaf094fc234c42f3c7f393d81 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 6 Feb 2024 13:46:46 +0100 Subject: [PATCH 04/40] Fix require command crashing at the end if no lock file is present, fixes #11814 --- src/Composer/Command/RequireCommand.php | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/Composer/Command/RequireCommand.php b/src/Composer/Command/RequireCommand.php index 4a8a47559f44..b7ee15681f55 100644 --- a/src/Composer/Command/RequireCommand.php +++ b/src/Composer/Command/RequireCommand.php @@ -558,13 +558,15 @@ private function updateRequirementsAfterResolution(array $requirementsToUpdate, throw new \RuntimeException('Unable to read '.$this->json->getPath().' contents to update the lock file hash.'); } $lockFile = Factory::getLockFile($this->json->getPath()); - $lockMtime = filemtime($lockFile); - $lock = new JsonFile($lockFile); - $lockData = $lock->read(); - $lockData['content-hash'] = Locker::getContentHash($contents); - $lock->write($lockData); - if (is_int($lockMtime)) { - @touch($lockFile, $lockMtime); + if (file_exists($lockFile)) { + $lockMtime = filemtime($lockFile); + $lock = new JsonFile($lockFile); + $lockData = $lock->read(); + $lockData['content-hash'] = Locker::getContentHash($contents); + $lock->write($lockData); + if (is_int($lockMtime)) { + @touch($lockFile, $lockMtime); + } } } } From ebb6a82099cc8b97765ecca627c5bc4ff8b0315b Mon Sep 17 00:00:00 2001 From: Derek Stephen McLean Date: Tue, 6 Feb 2024 16:53:18 +0100 Subject: [PATCH 05/40] issue #11811 auth token links on separate lines (#11812) * issue #11811 auth token links on separate lines * 11811 - remove stray bracket * 11811 : links on separte lines --- src/Composer/Util/Bitbucket.php | 3 ++- src/Composer/Util/GitHub.php | 6 ++++-- src/Composer/Util/GitLab.php | 14 +++++++++++--- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/Composer/Util/Bitbucket.php b/src/Composer/Util/Bitbucket.php index 1c9eeb65d7fc..2be4a815cb05 100644 --- a/src/Composer/Util/Bitbucket.php +++ b/src/Composer/Util/Bitbucket.php @@ -143,7 +143,8 @@ public function authorizeOAuthInteractively(string $originUrl, ?string $message $localAuthConfig = $this->config->getLocalAuthConfigSource(); $url = 'https://support.atlassian.com/bitbucket-cloud/docs/use-oauth-on-bitbucket-cloud/'; - $this->io->writeError(sprintf('Follow the instructions on %s', $url)); + $this->io->writeError('Follow the instructions here:'); + $this->io->writeError($url); $this->io->writeError(sprintf('to create a consumer. It will be stored in "%s" for future use by Composer.', ($localAuthConfig !== null ? $localAuthConfig->getName() . ' OR ' : '') . $this->config->getAuthConfigSource()->getName())); $this->io->writeError('Ensure you enter a "Callback URL" (http://example.com is fine) or it will not be possible to create an Access Token (this callback url will not be used by composer)'); diff --git a/src/Composer/Util/GitHub.php b/src/Composer/Util/GitHub.php index 43a635450c6a..3574e5183215 100644 --- a/src/Composer/Util/GitHub.php +++ b/src/Composer/Util/GitHub.php @@ -92,12 +92,14 @@ public function authorizeOAuthInteractively(string $originUrl, ?string $message $note .= ' ' . date('Y-m-d Hi'); $url = 'https://'.$originUrl.'/settings/tokens/new?scopes=&description=' . str_replace('%20', '+', rawurlencode($note)); - $this->io->writeError(sprintf('When working with _public_ GitHub repositories only, head to %s to retrieve a token.', $url)); + $this->io->writeError('When working with _public_ GitHub repositories only, head here to retrieve a token:'); + $this->io->writeError($url); $this->io->writeError('This token will have read-only permission for public information only.'); $localAuthConfig = $this->config->getLocalAuthConfigSource(); $url = 'https://'.$originUrl.'/settings/tokens/new?scopes=repo&description=' . str_replace('%20', '+', rawurlencode($note)); - $this->io->writeError(sprintf('When you need to access _private_ GitHub repositories as well, go to %s', $url)); + $this->io->writeError('When you need to access _private_ GitHub repositories as well, go to:'); + $this->io->writeError($url); $this->io->writeError('Note that such tokens have broad read/write permissions on your behalf, even if not needed by Composer.'); $this->io->writeError(sprintf('Tokens will be stored in plain text in "%s" for future use by Composer.', ($localAuthConfig !== null ? $localAuthConfig->getName() . ' OR ' : '') . $this->config->getAuthConfigSource()->getName())); $this->io->writeError('For additional information, check https://getcomposer.org/doc/articles/authentication-for-private-packages.md#github-oauth'); diff --git a/src/Composer/Util/GitLab.php b/src/Composer/Util/GitLab.php index 40b0fec00797..e5985c2db7fe 100644 --- a/src/Composer/Util/GitLab.php +++ b/src/Composer/Util/GitLab.php @@ -126,9 +126,16 @@ public function authorizeOAuthInteractively(string $scheme, string $originUrl, ? } $localAuthConfig = $this->config->getLocalAuthConfigSource(); + $personalAccessTokenLink = $scheme.'://'.$originUrl.'/-/profile/personal_access_tokens'; + $revokeLink = $scheme.'://'.$originUrl.'/-/profile/applications'; $this->io->writeError(sprintf('A token will be created and stored in "%s", your password will never be stored', ($localAuthConfig !== null ? $localAuthConfig->getName() . ' OR ' : '') . $this->config->getAuthConfigSource()->getName())); - $this->io->writeError('To revoke access to this token you can visit '.$scheme.'://'.$originUrl.'/-/profile/applications'); - $this->io->writeError('Alternatively you can setup an personal access token on '.$scheme.'://'.$originUrl.'/-/profile/personal_access_tokens and store it under "gitlab-token" see https://getcomposer.org/doc/articles/authentication-for-private-packages.md#gitlab-token for more details.'); + $this->io->writeError('To revoke access to this token you can visit:'); + $this->io->writeError($revokeLink); + $this->io->writeError('Alternatively you can setup an personal access token on:'); + $this->io->writeError($personalAccessTokenLink); + $this->io->writeError('and store it under "gitlab-token" see https://getcomposer.org/doc/articles/authentication-for-private-packages.md#gitlab-token for more details.'); + $this->io->writeError('https://getcomposer.org/doc/articles/authentication-for-private-packages.md#gitlab-token'); + $this->io->writeError('for more details.'); $storeInLocalAuthConfig = false; if ($localAuthConfig !== null) { @@ -155,7 +162,8 @@ public function authorizeOAuthInteractively(string $scheme, string $originUrl, ? $this->io->writeError('Maximum number of login attempts exceeded. Please try again later.'); } - $this->io->writeError('You can also manually create a personal access token enabling the "read_api" scope at '.$scheme.'://'.$originUrl.'/profile/personal_access_tokens'); + $this->io->writeError('You can also manually create a personal access token enabling the "read_api" scope at:'); + $this->io->writeError($scheme.'://'.$originUrl.'/profile/personal_access_tokens'); $this->io->writeError('Add it using "composer config --global --auth gitlab-token.'.$originUrl.' "'); continue; From e88c7a8987e9dcb5c614b6ca3c6bf4bcb309865c Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 6 Feb 2024 16:59:01 +0100 Subject: [PATCH 06/40] Add support for wildcards in outdated's --ignore arg, fixes #11831 --- doc/03-cli.md | 4 ++-- src/Composer/Command/OutdatedCommand.php | 2 +- src/Composer/Command/ShowCommand.php | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/03-cli.md b/doc/03-cli.md index 00734f605a2a..f72c2ba82211 100644 --- a/doc/03-cli.md +++ b/doc/03-cli.md @@ -562,7 +562,7 @@ php composer.phar show monolog/monolog 1.0.2 * **--tree (-t):** List your dependencies as a tree. If you pass a package name it will show the dependency tree for that package. * **--latest (-l):** List all installed packages including their latest version. * **--outdated (-o):** Implies --latest, but this lists *only* packages that have a newer version available. -* **--ignore:** Ignore specified package(s). Use it with the --outdated option if you don't want to be informed about new versions of some packages +* **--ignore:** Ignore specified package(s). Can contain wildcards (`*`). Use it with the --outdated option if you don't want to be informed about new versions of some packages * **--no-dev:** Filters dev dependencies from the package list. * **--major-only (-M):** Use with --latest or --outdated. Only shows packages that have major SemVer-compatible updates. * **--minor-only (-m):** Use with --latest or --outdated. Only shows packages that have minor SemVer-compatible updates. @@ -597,7 +597,7 @@ The color coding is as such: * **--all (-a):** Show all packages, not just outdated (alias for `composer show --latest`). * **--direct (-D):** Restricts the list of packages to your direct dependencies. * **--strict:** Returns non-zero exit code if any package is outdated. -* **--ignore:** Ignore specified package(s). Use it if you don't want to be informed about new versions of some packages +* **--ignore:** Ignore specified package(s). Can contain wildcards (`*`). Use it if you don't want to be informed about new versions of some packages * **--major-only (-M):** Only shows packages that have major SemVer-compatible updates. * **--minor-only (-m):** Only shows packages that have minor SemVer-compatible updates. * **--patch-only (-p):** Only shows packages that have patch-level SemVer-compatible updates. diff --git a/src/Composer/Command/OutdatedCommand.php b/src/Composer/Command/OutdatedCommand.php index b6c71c1753ad..139fe45a85ec 100644 --- a/src/Composer/Command/OutdatedCommand.php +++ b/src/Composer/Command/OutdatedCommand.php @@ -42,7 +42,7 @@ protected function configure(): void new InputOption('patch-only', 'p', InputOption::VALUE_NONE, 'Show only packages that have patch SemVer-compatible updates.'), new InputOption('sort-by-age', 'A', InputOption::VALUE_NONE, 'Displays the installed version\'s age, and sorts packages oldest first.'), new InputOption('format', 'f', InputOption::VALUE_REQUIRED, 'Format of the output: text or json', 'text', ['json', 'text']), - new InputOption('ignore', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Ignore specified package(s). Use it if you don\'t want to be informed about new versions of some packages.', null, $this->suggestInstalledPackage(false)), + new InputOption('ignore', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Ignore specified package(s). Can contain wildcards (*). Use it if you don\'t want to be informed about new versions of some packages.', null, $this->suggestInstalledPackage(false)), new InputOption('no-dev', null, InputOption::VALUE_NONE, 'Disables search in require-dev packages.'), new InputOption('ignore-platform-req', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Ignore a specific platform requirement (php & ext- packages). Use with the --outdated option'), new InputOption('ignore-platform-reqs', null, InputOption::VALUE_NONE, 'Ignore all platform requirements (php & ext- packages). Use with the --outdated option'), diff --git a/src/Composer/Command/ShowCommand.php b/src/Composer/Command/ShowCommand.php index fc5940b91587..542482554b6b 100644 --- a/src/Composer/Command/ShowCommand.php +++ b/src/Composer/Command/ShowCommand.php @@ -95,7 +95,7 @@ protected function configure() new InputOption('tree', 't', InputOption::VALUE_NONE, 'List the dependencies as a tree'), new InputOption('latest', 'l', InputOption::VALUE_NONE, 'Show the latest version'), new InputOption('outdated', 'o', InputOption::VALUE_NONE, 'Show the latest version but only for packages that are outdated'), - new InputOption('ignore', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Ignore specified package(s). Use it with the --outdated option if you don\'t want to be informed about new versions of some packages.', null, $this->suggestInstalledPackage(false)), + new InputOption('ignore', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Ignore specified package(s). Can contain wildcards (*). Use it with the --outdated option if you don\'t want to be informed about new versions of some packages.', null, $this->suggestInstalledPackage(false)), new InputOption('major-only', 'M', InputOption::VALUE_NONE, 'Show only packages that have major SemVer-compatible updates. Use with the --latest or --outdated option.'), new InputOption('minor-only', 'm', InputOption::VALUE_NONE, 'Show only packages that have minor SemVer-compatible updates. Use with the --latest or --outdated option.'), new InputOption('patch-only', null, InputOption::VALUE_NONE, 'Show only packages that have patch SemVer-compatible updates. Use with the --latest or --outdated option.'), @@ -459,7 +459,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $showMajorOnly = $input->getOption('major-only'); $showMinorOnly = $input->getOption('minor-only'); $showPatchOnly = $input->getOption('patch-only'); - $ignoredPackages = array_map('strtolower', $input->getOption('ignore')); + $ignoredPackagesRegex = BasePackage::packageNamesToRegexp(array_map('strtolower', $input->getOption('ignore'))); $indent = $showAllTypes ? ' ' : ''; /** @var PackageInterface[] $latestPackages */ $latestPackages = []; @@ -520,7 +520,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $packageIsUpToDate = $latestPackage && $latestPackage->getFullPrettyVersion() === $package->getFullPrettyVersion() && (!$latestPackage instanceof CompletePackageInterface || !$latestPackage->isAbandoned()); // When using --major-only, and no bigger version than current major is found then it is considered up to date $packageIsUpToDate = $packageIsUpToDate || ($latestPackage === null && $showMajorOnly); - $packageIsIgnored = \in_array($package->getPrettyName(), $ignoredPackages, true); + $packageIsIgnored = Preg::isMatch($ignoredPackagesRegex, $package->getPrettyName()); if ($input->getOption('outdated') && ($packageIsUpToDate || $packageIsIgnored)) { continue; } From 9a656854adf77fb984bb806986d493bba7f673fd Mon Sep 17 00:00:00 2001 From: Stephan Date: Tue, 6 Feb 2024 16:18:41 +0000 Subject: [PATCH 07/40] ValidatingArrayLoader: fix link validation with missing name (#11830) --- src/Composer/Package/Loader/ValidatingArrayLoader.php | 2 +- .../Test/Package/Loader/ValidatingArrayLoaderTest.php | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Composer/Package/Loader/ValidatingArrayLoader.php b/src/Composer/Package/Loader/ValidatingArrayLoader.php index 9f25ed2197f2..a94448a6159b 100644 --- a/src/Composer/Package/Loader/ValidatingArrayLoader.php +++ b/src/Composer/Package/Loader/ValidatingArrayLoader.php @@ -253,7 +253,7 @@ public function load(array $config, string $class = 'Composer\Package\CompletePa if ($this->validateArray($linkType) && isset($this->config[$linkType])) { foreach ($this->config[$linkType] as $package => $constraint) { $package = (string) $package; - if (0 === strcasecmp($package, $this->config['name'])) { + if (isset($this->config['name']) && 0 === strcasecmp($package, $this->config['name'])) { $this->errors[] = $linkType.'.'.$package.' : a package cannot set a '.$linkType.' on itself'; unset($this->config[$linkType][$package]); continue; diff --git a/tests/Composer/Test/Package/Loader/ValidatingArrayLoaderTest.php b/tests/Composer/Test/Package/Loader/ValidatingArrayLoaderTest.php index bcd029733633..40f05894e037 100644 --- a/tests/Composer/Test/Package/Loader/ValidatingArrayLoaderTest.php +++ b/tests/Composer/Test/Package/Loader/ValidatingArrayLoaderTest.php @@ -426,6 +426,12 @@ public static function errorProvider(): array ], ['replace.0 : invalid version constraint (Could not parse version constraint acme/bar: Invalid version string "acme/bar")'], ], + [ + [ + 'require' => ['acme/bar' => '^1.0'] + ], + ['name : must be present'], + ] ]); } From 7745d56c147f2abcee82a313f00e6b0a71d5ffa0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Wer=C5=82os?= Date: Wed, 7 Feb 2024 09:32:55 +0100 Subject: [PATCH 08/40] Do not show error that plugins have been disabled when they are already disabled (#11803) --- src/Composer/Console/Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Composer/Console/Application.php b/src/Composer/Console/Application.php index b747ea021a2e..774370b5178a 100644 --- a/src/Composer/Console/Application.php +++ b/src/Composer/Console/Application.php @@ -292,7 +292,7 @@ public function doRun(InputInterface $input, OutputInterface $output): int $this->hasPluginCommands = true; } - if ($isNonAllowedRoot && !$io->isInteractive()) { + if (!$this->disablePluginsByDefault && $isNonAllowedRoot && !$io->isInteractive()) { $io->writeError('Composer plugins have been disabled for safety in this non-interactive session. Set COMPOSER_ALLOW_SUPERUSER=1 if you want to allow plugins to run as root/super user.'); $this->disablePluginsByDefault = true; } From d0b465ffd0299aea2b8fd832c402cc8e1f2bee1b Mon Sep 17 00:00:00 2001 From: Antoine M Date: Wed, 7 Feb 2024 10:10:05 +0100 Subject: [PATCH 09/40] chore(doc): add `_comment` documentation inside `composer.json` schema (#11825) * Update 04-schema.md * example --- doc/04-schema.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/doc/04-schema.md b/doc/04-schema.md index 6bd169cf9b54..e36ec21115b9 100644 --- a/doc/04-schema.md +++ b/doc/04-schema.md @@ -967,6 +967,23 @@ Defaults to false. Optional. +### _comment + +Top level key used as a place to store comments (it can be a string or array of strings). + +```json +{ + "_comment": [ + "The package foo/bar was required for business logic", + "Remove package foo/baz when removing foo/bar" + ] +} +``` + +Defaults to empty. + +Optional. + ### non-feature-branches A list of regex patterns of branch names that are non-numeric (e.g. "latest" or something), From 158df56cccb248a5a2c50a0f2ad7fdc526fb6925 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 7 Feb 2024 10:10:42 +0100 Subject: [PATCH 10/40] Bump actions/cache from 3 to 4 (#11807) Bumps [actions/cache](https://github.com/actions/cache) from 3 to 4. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/phpstan.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml index b6300137f5f1..a4c25379a3ba 100644 --- a/.github/workflows/phpstan.yml +++ b/.github/workflows/phpstan.yml @@ -48,7 +48,7 @@ jobs: run: "echo \"directory=$(composer config cache-dir)\" >> $GITHUB_OUTPUT" - name: "Cache dependencies installed with composer" - uses: "actions/cache@v3" + uses: "actions/cache@v4" with: path: "${{ steps.determine-composer-cache-directory.outputs.directory }}" key: "php-${{ matrix.php-version }}-symfony-php-unit-version-${{ env.SYMFONY_PHPUNIT_VERSION }}-${{ hashFiles('**/composer.lock') }}" From 654da6f576519bf4b254b7b13f7a7dd2cfbe9e30 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 7 Feb 2024 11:10:21 +0100 Subject: [PATCH 11/40] Update deps, fixes #11801 --- composer.lock | 199 ++++++++++++++++++++++---------------------------- 1 file changed, 89 insertions(+), 110 deletions(-) diff --git a/composer.lock b/composer.lock index bd2f57c9c6c4..559544311aec 100644 --- a/composer.lock +++ b/composer.lock @@ -938,16 +938,16 @@ }, { "name": "symfony/console", - "version": "v5.4.34", + "version": "v5.4.35", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "4b4d8cd118484aa604ec519062113dd87abde18c" + "reference": "dbdf6adcb88d5f83790e1efb57ef4074309d3931" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/4b4d8cd118484aa604ec519062113dd87abde18c", - "reference": "4b4d8cd118484aa604ec519062113dd87abde18c", + "url": "https://api.github.com/repos/symfony/console/zipball/dbdf6adcb88d5f83790e1efb57ef4074309d3931", + "reference": "dbdf6adcb88d5f83790e1efb57ef4074309d3931", "shasum": "" }, "require": { @@ -1017,7 +1017,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v5.4.34" + "source": "https://github.com/symfony/console/tree/v5.4.35" }, "funding": [ { @@ -1033,7 +1033,7 @@ "type": "tidelift" } ], - "time": "2023-12-08T13:33:03+00:00" + "time": "2024-01-23T14:28:09+00:00" }, { "name": "symfony/deprecation-contracts", @@ -1104,16 +1104,16 @@ }, { "name": "symfony/filesystem", - "version": "v5.4.25", + "version": "v5.4.35", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "0ce3a62c9579a53358d3a7eb6b3dfb79789a6364" + "reference": "5a553607d4ffbfa9c0ab62facadea296c9db7086" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/0ce3a62c9579a53358d3a7eb6b3dfb79789a6364", - "reference": "0ce3a62c9579a53358d3a7eb6b3dfb79789a6364", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/5a553607d4ffbfa9c0ab62facadea296c9db7086", + "reference": "5a553607d4ffbfa9c0ab62facadea296c9db7086", "shasum": "" }, "require": { @@ -1148,7 +1148,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v5.4.25" + "source": "https://github.com/symfony/filesystem/tree/v5.4.35" }, "funding": [ { @@ -1164,20 +1164,20 @@ "type": "tidelift" } ], - "time": "2023-05-31T13:04:02+00:00" + "time": "2024-01-23T13:51:25+00:00" }, { "name": "symfony/finder", - "version": "v5.4.27", + "version": "v5.4.35", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "ff4bce3c33451e7ec778070e45bd23f74214cd5d" + "reference": "abe6d6f77d9465fed3cd2d029b29d03b56b56435" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/ff4bce3c33451e7ec778070e45bd23f74214cd5d", - "reference": "ff4bce3c33451e7ec778070e45bd23f74214cd5d", + "url": "https://api.github.com/repos/symfony/finder/zipball/abe6d6f77d9465fed3cd2d029b29d03b56b56435", + "reference": "abe6d6f77d9465fed3cd2d029b29d03b56b56435", "shasum": "" }, "require": { @@ -1211,7 +1211,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v5.4.27" + "source": "https://github.com/symfony/finder/tree/v5.4.35" }, "funding": [ { @@ -1227,20 +1227,20 @@ "type": "tidelift" } ], - "time": "2023-07-31T08:02:31+00:00" + "time": "2024-01-23T13:51:25+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.28.0", + "version": "v1.29.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb" + "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", - "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ef4d7e442ca910c4764bce785146269b30cb5fc4", + "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4", "shasum": "" }, "require": { @@ -1254,9 +1254,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -1293,7 +1290,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.29.0" }, "funding": [ { @@ -1309,20 +1306,20 @@ "type": "tidelift" } ], - "time": "2023-01-26T09:26:14+00:00" + "time": "2024-01-29T20:11:03+00:00" }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.28.0", + "version": "v1.29.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "875e90aeea2777b6f135677f618529449334a612" + "reference": "32a9da87d7b3245e09ac426c83d334ae9f06f80f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/875e90aeea2777b6f135677f618529449334a612", - "reference": "875e90aeea2777b6f135677f618529449334a612", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/32a9da87d7b3245e09ac426c83d334ae9f06f80f", + "reference": "32a9da87d7b3245e09ac426c83d334ae9f06f80f", "shasum": "" }, "require": { @@ -1333,9 +1330,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -1374,7 +1368,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.29.0" }, "funding": [ { @@ -1390,20 +1384,20 @@ "type": "tidelift" } ], - "time": "2023-01-26T09:26:14+00:00" + "time": "2024-01-29T20:11:03+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.28.0", + "version": "v1.29.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92" + "reference": "bc45c394692b948b4d383a08d7753968bed9a83d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92", - "reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/bc45c394692b948b4d383a08d7753968bed9a83d", + "reference": "bc45c394692b948b4d383a08d7753968bed9a83d", "shasum": "" }, "require": { @@ -1414,9 +1408,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -1458,7 +1449,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.29.0" }, "funding": [ { @@ -1474,20 +1465,20 @@ "type": "tidelift" } ], - "time": "2023-01-26T09:26:14+00:00" + "time": "2024-01-29T20:11:03+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.28.0", + "version": "v1.29.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "42292d99c55abe617799667f454222c54c60e229" + "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229", - "reference": "42292d99c55abe617799667f454222c54c60e229", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9773676c8a1bb1f8d4340a62efe641cf76eda7ec", + "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec", "shasum": "" }, "require": { @@ -1501,9 +1492,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -1541,7 +1529,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.29.0" }, "funding": [ { @@ -1557,20 +1545,20 @@ "type": "tidelift" } ], - "time": "2023-07-28T09:04:16+00:00" + "time": "2024-01-29T20:11:03+00:00" }, { "name": "symfony/polyfill-php73", - "version": "v1.28.0", + "version": "v1.29.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "fe2f306d1d9d346a7fee353d0d5012e401e984b5" + "reference": "21bd091060673a1177ae842c0ef8fe30893114d2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/fe2f306d1d9d346a7fee353d0d5012e401e984b5", - "reference": "fe2f306d1d9d346a7fee353d0d5012e401e984b5", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/21bd091060673a1177ae842c0ef8fe30893114d2", + "reference": "21bd091060673a1177ae842c0ef8fe30893114d2", "shasum": "" }, "require": { @@ -1578,9 +1566,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -1620,7 +1605,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-php73/tree/v1.29.0" }, "funding": [ { @@ -1636,20 +1621,20 @@ "type": "tidelift" } ], - "time": "2023-01-26T09:26:14+00:00" + "time": "2024-01-29T20:11:03+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.28.0", + "version": "v1.29.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5" + "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/6caa57379c4aec19c0a12a38b59b26487dcfe4b5", - "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/87b68208d5c1188808dd7839ee1e6c8ec3b02f1b", + "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b", "shasum": "" }, "require": { @@ -1657,9 +1642,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -1703,7 +1685,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.29.0" }, "funding": [ { @@ -1719,20 +1701,20 @@ "type": "tidelift" } ], - "time": "2023-01-26T09:26:14+00:00" + "time": "2024-01-29T20:11:03+00:00" }, { "name": "symfony/polyfill-php81", - "version": "v1.28.0", + "version": "v1.29.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php81.git", - "reference": "7581cd600fa9fd681b797d00b02f068e2f13263b" + "reference": "c565ad1e63f30e7477fc40738343c62b40bc672d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/7581cd600fa9fd681b797d00b02f068e2f13263b", - "reference": "7581cd600fa9fd681b797d00b02f068e2f13263b", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/c565ad1e63f30e7477fc40738343c62b40bc672d", + "reference": "c565ad1e63f30e7477fc40738343c62b40bc672d", "shasum": "" }, "require": { @@ -1740,9 +1722,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -1782,7 +1761,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php81/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-php81/tree/v1.29.0" }, "funding": [ { @@ -1798,20 +1777,20 @@ "type": "tidelift" } ], - "time": "2023-01-26T09:26:14+00:00" + "time": "2024-01-29T20:11:03+00:00" }, { "name": "symfony/process", - "version": "v5.4.34", + "version": "v5.4.35", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "8fa22178dfc368911dbd513b431cd9b06f9afe7a" + "reference": "cbc28e34015ad50166fc2f9c8962d28d0fe861eb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/8fa22178dfc368911dbd513b431cd9b06f9afe7a", - "reference": "8fa22178dfc368911dbd513b431cd9b06f9afe7a", + "url": "https://api.github.com/repos/symfony/process/zipball/cbc28e34015ad50166fc2f9c8962d28d0fe861eb", + "reference": "cbc28e34015ad50166fc2f9c8962d28d0fe861eb", "shasum": "" }, "require": { @@ -1844,7 +1823,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v5.4.34" + "source": "https://github.com/symfony/process/tree/v5.4.35" }, "funding": [ { @@ -1860,7 +1839,7 @@ "type": "tidelift" } ], - "time": "2023-12-02T08:41:43+00:00" + "time": "2024-01-23T13:51:25+00:00" }, { "name": "symfony/service-contracts", @@ -1947,16 +1926,16 @@ }, { "name": "symfony/string", - "version": "v5.4.34", + "version": "v5.4.35", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "e3f98bfc7885c957488f443df82d97814a3ce061" + "reference": "c209c4d0559acce1c9a2067612cfb5d35756edc2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/e3f98bfc7885c957488f443df82d97814a3ce061", - "reference": "e3f98bfc7885c957488f443df82d97814a3ce061", + "url": "https://api.github.com/repos/symfony/string/zipball/c209c4d0559acce1c9a2067612cfb5d35756edc2", + "reference": "c209c4d0559acce1c9a2067612cfb5d35756edc2", "shasum": "" }, "require": { @@ -2013,7 +1992,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v5.4.34" + "source": "https://github.com/symfony/string/tree/v5.4.35" }, "funding": [ { @@ -2029,22 +2008,22 @@ "type": "tidelift" } ], - "time": "2023-12-09T13:20:28+00:00" + "time": "2024-01-23T13:51:25+00:00" } ], "packages-dev": [ { "name": "phpstan/phpstan", - "version": "1.10.55", + "version": "1.10.57", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "9a88f9d18ddf4cf54c922fbeac16c4cb164c5949" + "reference": "1627b1d03446904aaa77593f370c5201d2ecc34e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/9a88f9d18ddf4cf54c922fbeac16c4cb164c5949", - "reference": "9a88f9d18ddf4cf54c922fbeac16c4cb164c5949", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/1627b1d03446904aaa77593f370c5201d2ecc34e", + "reference": "1627b1d03446904aaa77593f370c5201d2ecc34e", "shasum": "" }, "require": { @@ -2093,7 +2072,7 @@ "type": "tidelift" } ], - "time": "2024-01-08T12:32:40+00:00" + "time": "2024-01-24T11:51:34+00:00" }, { "name": "phpstan/phpstan-deprecation-rules", @@ -2246,16 +2225,16 @@ }, { "name": "phpstan/phpstan-symfony", - "version": "1.3.6", + "version": "1.3.7", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-symfony.git", - "reference": "34b3c43684834f6a20aa51af8d455480d9de8b88" + "reference": "ef7db637be9b85fa00278fc3477ac66abe8eb7d1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-symfony/zipball/34b3c43684834f6a20aa51af8d455480d9de8b88", - "reference": "34b3c43684834f6a20aa51af8d455480d9de8b88", + "url": "https://api.github.com/repos/phpstan/phpstan-symfony/zipball/ef7db637be9b85fa00278fc3477ac66abe8eb7d1", + "reference": "ef7db637be9b85fa00278fc3477ac66abe8eb7d1", "shasum": "" }, "require": { @@ -2312,22 +2291,22 @@ "description": "Symfony Framework extensions and rules for PHPStan", "support": { "issues": "https://github.com/phpstan/phpstan-symfony/issues", - "source": "https://github.com/phpstan/phpstan-symfony/tree/1.3.6" + "source": "https://github.com/phpstan/phpstan-symfony/tree/1.3.7" }, - "time": "2023-12-22T11:22:34+00:00" + "time": "2024-01-10T21:54:42+00:00" }, { "name": "symfony/phpunit-bridge", - "version": "v7.0.2", + "version": "v7.0.3", "source": { "type": "git", "url": "https://github.com/symfony/phpunit-bridge.git", - "reference": "92df075808c9437beca9540e25ae0c40eea1c061" + "reference": "0a2eeb0d9e68bf01660e3e903f8113508bb46132" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/92df075808c9437beca9540e25ae0c40eea1c061", - "reference": "92df075808c9437beca9540e25ae0c40eea1c061", + "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/0a2eeb0d9e68bf01660e3e903f8113508bb46132", + "reference": "0a2eeb0d9e68bf01660e3e903f8113508bb46132", "shasum": "" }, "require": { @@ -2379,7 +2358,7 @@ "description": "Provides utilities for PHPUnit, especially user deprecation notices management", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/phpunit-bridge/tree/v7.0.2" + "source": "https://github.com/symfony/phpunit-bridge/tree/v7.0.3" }, "funding": [ { @@ -2395,7 +2374,7 @@ "type": "tidelift" } ], - "time": "2023-12-19T11:23:03+00:00" + "time": "2024-01-23T15:02:46+00:00" } ], "aliases": [], From fd233813918fba2e17c3cb9826a3fd0e729e6a16 Mon Sep 17 00:00:00 2001 From: PrinsFrank <25006490+PrinsFrank@users.noreply.github.com> Date: Wed, 7 Feb 2024 11:11:16 +0100 Subject: [PATCH 12/40] Add arguments to command call output (#11826) --- src/Composer/EventDispatcher/EventDispatcher.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Composer/EventDispatcher/EventDispatcher.php b/src/Composer/EventDispatcher/EventDispatcher.php index 3326b8e31792..acc20beda9c1 100644 --- a/src/Composer/EventDispatcher/EventDispatcher.php +++ b/src/Composer/EventDispatcher/EventDispatcher.php @@ -194,6 +194,7 @@ protected function doDispatch(Event $event) $return = 0; $this->ensureBinDirIsInPath(); + $formattedEventNameWithArgs = $event->getName() . ($event->getArguments() !== [] ? ' (' . implode(', ', $event->getArguments()) . ')' : ''); if (!is_string($callable)) { if (!is_callable($callable)) { $className = is_object($callable[0]) ? get_class($callable[0]) : $callable[0]; @@ -201,11 +202,11 @@ protected function doDispatch(Event $event) throw new \RuntimeException('Subscriber '.$className.'::'.$callable[1].' for event '.$event->getName().' is not callable, make sure the function is defined and public'); } if (is_array($callable) && (is_string($callable[0]) || is_object($callable[0])) && is_string($callable[1])) { - $this->io->writeError(sprintf('> %s: %s', $event->getName(), (is_object($callable[0]) ? get_class($callable[0]) : $callable[0]).'->'.$callable[1]), true, IOInterface::VERBOSE); + $this->io->writeError(sprintf('> %s: %s', $formattedEventNameWithArgs, (is_object($callable[0]) ? get_class($callable[0]) : $callable[0]).'->'.$callable[1]), true, IOInterface::VERBOSE); } $return = false === $callable($event) ? 1 : 0; } elseif ($this->isComposerScript($callable)) { - $this->io->writeError(sprintf('> %s: %s', $event->getName(), $callable), true, IOInterface::VERBOSE); + $this->io->writeError(sprintf('> %s: %s', $formattedEventNameWithArgs, $callable), true, IOInterface::VERBOSE); $script = explode(' ', substr($callable, 1)); $scriptName = $script[0]; From fa040131b0ad4ede430cdf5dd9e68ef53cd82c54 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 7 Feb 2024 11:17:54 +0100 Subject: [PATCH 13/40] Add more details to event debug output, refs #11818 --- src/Composer/EventDispatcher/EventDispatcher.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Composer/EventDispatcher/EventDispatcher.php b/src/Composer/EventDispatcher/EventDispatcher.php index acc20beda9c1..b91b4e8edb7f 100644 --- a/src/Composer/EventDispatcher/EventDispatcher.php +++ b/src/Composer/EventDispatcher/EventDispatcher.php @@ -20,6 +20,8 @@ use Composer\Composer; use Composer\PartialComposer; use Composer\Pcre\Preg; +use Composer\Plugin\CommandEvent; +use Composer\Plugin\PreCommandRunEvent; use Composer\Util\Platform; use Composer\DependencyResolver\Operation\OperationInterface; use Composer\Repository\RepositoryInterface; @@ -180,6 +182,10 @@ protected function doDispatch(Event $event) $details = null; if ($event instanceof PackageEvent) { $details = (string) $event->getOperation(); + } elseif ($event instanceof CommandEvent) { + $details = $event->getCommandName(); + } elseif ($event instanceof PreCommandRunEvent) { + $details = $event->getCommand(); } $this->io->writeError('Dispatching '.$event->getName().''.($details ? ' ('.$details.')' : '').' event'); } From 0c99bfc8fd2724696cb54560daac1fe7787a4729 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 7 Feb 2024 11:37:50 +0100 Subject: [PATCH 14/40] Fix root aliases causing problems when auditing locked dependencies, fixes #11771 --- src/Composer/Repository/RepositorySet.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Composer/Repository/RepositorySet.php b/src/Composer/Repository/RepositorySet.php index 9940d0850041..48cf424a4f8a 100644 --- a/src/Composer/Repository/RepositorySet.php +++ b/src/Composer/Repository/RepositorySet.php @@ -30,6 +30,7 @@ use Composer\Semver\Constraint\ConstraintInterface; use Composer\Package\Version\StabilityFilter; use Composer\Semver\Constraint\MatchAllConstraint; +use Composer\Semver\Constraint\MultiConstraint; /** * @author Nils Adermann @@ -245,7 +246,15 @@ public function getMatchingSecurityAdvisories(array $packages, bool $allowPartia { $map = []; foreach ($packages as $package) { - $map[$package->getName()] = new Constraint('=', $package->getVersion()); + // ignore root alias versions as they are not actual package versions and should not matter when it comes to vulnerabilities + if ($package instanceof AliasPackage && $package->isRootPackageAlias()) { + continue; + } + if (isset($map[$package->getName()])) { + $map[$package->getName()] = new MultiConstraint([new Constraint('=', $package->getVersion()), $map[$package->getName()]], false); + } else { + $map[$package->getName()] = new Constraint('=', $package->getVersion()); + } } return $this->getSecurityAdvisoriesForConstraints($map, $allowPartialAdvisories); From 338bc16a115d866b108b38399562b06c988cd93f Mon Sep 17 00:00:00 2001 From: theoboldalex <44616505+theoboldalex@users.noreply.github.com> Date: Wed, 7 Feb 2024 10:40:29 +0000 Subject: [PATCH 15/40] test: Covers audit of pkg with no sec advisories (#11789) --- tests/Composer/Test/Command/AuditCommandTest.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/Composer/Test/Command/AuditCommandTest.php b/tests/Composer/Test/Command/AuditCommandTest.php index 53041f33d5f1..6bf751fabcec 100644 --- a/tests/Composer/Test/Command/AuditCommandTest.php +++ b/tests/Composer/Test/Command/AuditCommandTest.php @@ -41,4 +41,20 @@ public function testErrorAuditingLockFileWhenItIsMissing(): void $appTester = $this->getApplicationTester(); $appTester->run(['command' => 'audit', '--locked' => true]); } + + public function testAuditPackageWithNoSecurityVulnerabilities(): void + { + $this->initTempComposer(); + $packages = [self::getPackage()]; + $this->createInstalledJson($packages); + $this->createComposerLock($packages); + + $appTester = $this->getApplicationTester(); + $appTester->run(['command' => 'audit', '--locked' => true]); + + self::assertStringContainsString( + 'No security vulnerability advisories found.', + trim($appTester->getDisplay(true)) + ); + } } From 18cd8a01a4ff8ab2b6586f6c467962553cf3f9c7 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 7 Feb 2024 14:06:15 +0100 Subject: [PATCH 16/40] Update jsonlint --- composer.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/composer.lock b/composer.lock index 559544311aec..04c822b48fea 100644 --- a/composer.lock +++ b/composer.lock @@ -765,16 +765,16 @@ }, { "name": "seld/jsonlint", - "version": "1.10.1", + "version": "1.10.2", "source": { "type": "git", "url": "https://github.com/Seldaek/jsonlint.git", - "reference": "76d449a358ece77d6f1d6331c68453e657172202" + "reference": "9bb7db07b5d66d90f6ebf542f09fc67d800e5259" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/76d449a358ece77d6f1d6331c68453e657172202", - "reference": "76d449a358ece77d6f1d6331c68453e657172202", + "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/9bb7db07b5d66d90f6ebf542f09fc67d800e5259", + "reference": "9bb7db07b5d66d90f6ebf542f09fc67d800e5259", "shasum": "" }, "require": { @@ -813,7 +813,7 @@ ], "support": { "issues": "https://github.com/Seldaek/jsonlint/issues", - "source": "https://github.com/Seldaek/jsonlint/tree/1.10.1" + "source": "https://github.com/Seldaek/jsonlint/tree/1.10.2" }, "funding": [ { @@ -825,7 +825,7 @@ "type": "tidelift" } ], - "time": "2023-12-18T13:03:25+00:00" + "time": "2024-02-07T12:57:50+00:00" }, { "name": "seld/phar-utils", From e0807d381ebc90f1d1570e7751700374d3dcbfc7 Mon Sep 17 00:00:00 2001 From: Ayesh Karunaratne Date: Thu, 8 Feb 2024 03:30:24 +0700 Subject: [PATCH 17/40] Diagnose command: Add GitHub OAuth token expiration date information (#11688) GitHub's new fine-grained tokens have a cumpulsory expiration date, and their classic tokens also support an expiration date. https://github.blog/changelog/2021-07-26-expiration-options-for-personal-access-tokens/ This improves the `composer diagnose` command to display the expiration date and time if it is provided by the response headers (via `GitHub-Authentication-Token-Expiration`). --- src/Composer/Command/DiagnoseCommand.php | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/Composer/Command/DiagnoseCommand.php b/src/Composer/Command/DiagnoseCommand.php index 18b1911d75bd..fc594f7d94f7 100644 --- a/src/Composer/Command/DiagnoseCommand.php +++ b/src/Composer/Command/DiagnoseCommand.php @@ -326,7 +326,7 @@ private function checkHttpProxy() } /** - * @return string|true|\Exception + * @return string|\Exception */ private function checkGithubOauth(string $domain, string $token) { @@ -339,11 +339,17 @@ private function checkGithubOauth(string $domain, string $token) try { $url = $domain === 'github.com' ? 'https://api.'.$domain.'/' : 'https://'.$domain.'/api/v3/'; - $this->httpDownloader->get($url, [ + $response = $this->httpDownloader->get($url, [ 'retry-auth-failure' => false, ]); - return true; + $expiration = $response->getHeader('github-authentication-token-expiration'); + + if ($expiration === null) { + return 'OK does not expire'; + } + + return 'OK expires on '. $expiration .''; } catch (\Exception $e) { if ($e instanceof TransportException && $e->getCode() === 401) { return 'The oauth token for '.$domain.' seems invalid, run "composer config --global --unset github-oauth.'.$domain.'" to remove it'; From 7cb92a90c8ce1fc8816078bb82f9caa180d082fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dezs=C5=91=20BICZ=C3=93?= Date: Wed, 7 Feb 2024 21:13:36 +0000 Subject: [PATCH 18/40] Introduce COMPOSER_AUDIT_ABANDONED env var (#11794) Co-authored-by: Jordi Boggiano --- doc/03-cli.md | 5 ++++ doc/06-config.md | 12 ++++++++++ src/Composer/Advisory/Auditor.php | 1 + src/Composer/Config.php | 14 +++++++++++ tests/Composer/Test/Advisory/AuditorTest.php | 1 + tests/Composer/Test/ConfigTest.php | 25 ++++++++++++++++++++ 6 files changed, 58 insertions(+) diff --git a/doc/03-cli.md b/doc/03-cli.md index f72c2ba82211..b03ad1f8c3fc 100644 --- a/doc/03-cli.md +++ b/doc/03-cli.md @@ -1247,6 +1247,11 @@ similar use case), and need to support proxies, please provide the `CGI_HTTP_PRO environment variable instead. See [httpoxy.org](https://httpoxy.org/) for further details. +### COMPOSER_AUDIT_ABANDONED + +Set to `ignore`, `report` or `fail` to override the [audit.abandoned](06-config.md#abandoned) +config option. + ### COMPOSER_MAX_PARALLEL_HTTP Set to an integer to configure how many files can be downloaded in parallel. This diff --git a/doc/06-config.md b/doc/06-config.md index a39c2872b44f..c6aa47491db1 100644 --- a/doc/06-config.md +++ b/doc/06-config.md @@ -143,6 +143,18 @@ Defaults to `report` in Composer 2.6, and defaults to `fail` from Composer 2.7 o - `report` means abandoned packages are reported as an error but do not cause the command to exit with a non-zero code. - `fail` means abandoned packages will cause audits to fail with a non-zero code. +```json +{ + "config": { + "audit": { + "abandoned": "report" + } + } +} +``` + +Since Composer 2.7 the option can be overriden via the [`COMPOSER_AUDIT_ABANDONED`](03-cli.md#composer-audit-abandoned) environment variable. + ## use-parent-dir When running Composer in a directory where there is no composer.json, if there diff --git a/src/Composer/Advisory/Auditor.php b/src/Composer/Advisory/Auditor.php index bc6520d55ffb..f0dc76ae5ad3 100644 --- a/src/Composer/Advisory/Auditor.php +++ b/src/Composer/Advisory/Auditor.php @@ -19,6 +19,7 @@ use Composer\Package\PackageInterface; use Composer\Repository\RepositorySet; use Composer\Util\PackageInfo; +use Composer\Util\Platform; use InvalidArgumentException; use Symfony\Component\Console\Formatter\OutputFormatter; diff --git a/src/Composer/Config.php b/src/Composer/Config.php index 9296467f472f..f9da7d30475e 100644 --- a/src/Composer/Config.php +++ b/src/Composer/Config.php @@ -436,6 +436,20 @@ public function get(string $key, int $flags = 0) return $this->process($this->config[$key], $flags); + case 'audit': + $result = $this->config[$key]; + $abandonedEnv = $this->getComposerEnv('COMPOSER_AUDIT_ABANDONED'); + if (false !== $abandonedEnv) { + if (!in_array($abandonedEnv, $validChoices = [Auditor::ABANDONED_IGNORE, Auditor::ABANDONED_REPORT, Auditor::ABANDONED_FAIL], true)) { + throw new \RuntimeException( + "Invalid value for COMPOSER_AUDIT_ABANDONED: {$abandonedEnv}. Expected ".Auditor::ABANDONED_IGNORE.", ".Auditor::ABANDONED_REPORT." or ".Auditor::ABANDONED_FAIL + ); + } + $result['abandoned'] = $abandonedEnv; + } + + return $result; + default: if (!isset($this->config[$key])) { return null; diff --git a/tests/Composer/Test/Advisory/AuditorTest.php b/tests/Composer/Test/Advisory/AuditorTest.php index 2253169f4934..748f6a5f8055 100644 --- a/tests/Composer/Test/Advisory/AuditorTest.php +++ b/tests/Composer/Test/Advisory/AuditorTest.php @@ -23,6 +23,7 @@ use Composer\Repository\RepositorySet; use Composer\Test\TestCase; use Composer\Advisory\Auditor; +use Composer\Util\Platform; use InvalidArgumentException; class AuditorTest extends TestCase diff --git a/tests/Composer/Test/ConfigTest.php b/tests/Composer/Test/ConfigTest.php index 428c4f26558d..8a169b745a3d 100644 --- a/tests/Composer/Test/ConfigTest.php +++ b/tests/Composer/Test/ConfigTest.php @@ -12,6 +12,7 @@ namespace Composer\Test; +use Composer\Advisory\Auditor; use Composer\Config; use Composer\IO\IOInterface; use Composer\Util\Platform; @@ -382,6 +383,30 @@ public function testGetSourceOfValueEnvVariables(): void $this->assertEquals('COMPOSER_HTACCESS_PROTECT', $result); } + public function testAudit(): void + { + $config = new Config(true); + $result = $config->get('audit'); + self::assertArrayHasKey('abandoned', $result); + self::assertArrayHasKey('ignore', $result); + self::assertSame(Auditor::ABANDONED_FAIL, $result['abandoned']); + self::assertSame([], $result['ignore']); + + Platform::putEnv('COMPOSER_AUDIT_ABANDONED', Auditor::ABANDONED_IGNORE); + $result = $config->get('audit'); + Platform::clearEnv('COMPOSER_AUDIT_ABANDONED'); + self::assertArrayHasKey('abandoned', $result); + self::assertArrayHasKey('ignore', $result); + self::assertSame(Auditor::ABANDONED_IGNORE, $result['abandoned']); + self::assertSame([], $result['ignore']); + + $config->merge(['config' => ['audit' => ['ignore' => ['A', 'B']]]]); + $config->merge(['config' => ['audit' => ['ignore' => ['A', 'C']]]]); + $result = $config->get('audit'); + self::assertArrayHasKey('ignore', $result); + self::assertSame(['A', 'B', 'A', 'C'], $result['ignore']); + } + public function testGetDefaultsToAnEmptyArray(): void { $config = new Config; From 754f2868fbfa8dac2a7542d9132523c9396c87a2 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 7 Feb 2024 22:27:39 +0100 Subject: [PATCH 19/40] Add non-zero return codes when why-not finds a reason a package is not installable, or when why finds no reason it is there, fixes #11796 --- src/Composer/Command/BaseDependencyCommand.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Composer/Command/BaseDependencyCommand.php b/src/Composer/Command/BaseDependencyCommand.php index e010c122a83c..2fb363979c10 100644 --- a/src/Composer/Command/BaseDependencyCommand.php +++ b/src/Composer/Command/BaseDependencyCommand.php @@ -133,6 +133,8 @@ protected function doExecute(InputInterface $input, OutputInterface $output, boo $renderTree = $input->getOption(self::OPTION_TREE); $recursive = $renderTree || $input->getOption(self::OPTION_RECURSIVE); + $return = $inverted ? 1 : 0; + // Resolve dependencies $results = $installedRepo->getDependents($needles, $constraint, $inverted, $recursive); if (empty($results)) { @@ -142,6 +144,7 @@ protected function doExecute(InputInterface $input, OutputInterface $output, boo $needle, $extra )); + $return = $inverted ? 0 : 1; } elseif ($renderTree) { $this->initStyles($output); $root = $packages[0]; @@ -171,7 +174,7 @@ protected function doExecute(InputInterface $input, OutputInterface $output, boo $this->getIO()->writeError('Not finding what you were looking for? Try calling `composer '.$composerCommand.' "'.$needle.':'.$textConstraint.'" --dry-run` to get another view on the problem.'); } - return 0; + return $return; } /** From df8f9f05a310b3670fbd9d14eac4f57d2e9115b4 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 7 Feb 2024 22:37:22 +0100 Subject: [PATCH 20/40] Update tests --- .../Command/BaseDependencyCommandTest.php | 55 +++++++++++-------- tests/Composer/Test/TestCase.php | 8 +++ 2 files changed, 40 insertions(+), 23 deletions(-) diff --git a/tests/Composer/Test/Command/BaseDependencyCommandTest.php b/tests/Composer/Test/Command/BaseDependencyCommandTest.php index 8b0230dfc571..4201caa3eaa3 100644 --- a/tests/Composer/Test/Command/BaseDependencyCommandTest.php +++ b/tests/Composer/Test/Command/BaseDependencyCommandTest.php @@ -228,7 +228,7 @@ public static function caseProvider(): Generator * * @param array $parameters */ - public function testWhyCommandOutputs(array $parameters, string $expectedOutput): void + public function testWhyCommandOutputs(array $parameters, string $expectedOutput, int $expectedStatusCode): void { $packageToBeInspected = $parameters['package']; $renderAsTree = $parameters['--tree'] ?? false; @@ -294,9 +294,9 @@ public function testWhyCommandOutputs(array $parameters, string $expectedOutput) '--locked' => true ]); - $appTester->assertCommandIsSuccessful(); + self::assertSame($expectedStatusCode, $appTester->getStatusCode()); - $this->assertEquals(trim($expectedOutput), trim($appTester->getDisplay(true))); + $this->assertEquals(trim($expectedOutput), $this->trimLines($appTester->getDisplay(true))); } /** @@ -306,41 +306,46 @@ public static function caseWhyProvider(): Generator { yield 'there is no installed package depending on the package' => [ ['package' => 'vendor1/package1'], - 'There is no installed package depending on "vendor1/package1"' + 'There is no installed package depending on "vendor1/package1"', + 1 ]; yield 'a nested package dependency' => [ ['package' => 'vendor1/package3'], << [ ['package' => 'vendor1/package3', '--tree' => true], << [ ['package' => 'vendor1/package3', '--recursive' => true], << [ ['package' => 'vendor2/package1'], - '__root__ - requires (for development) vendor2/package1 (2.*)' + '__root__ - requires (for development) vendor2/package1 (2.*)', + 0 ]; } @@ -354,7 +359,7 @@ public static function caseWhyProvider(): Generator * * @param array $parameters */ - public function testWhyNotCommandOutputs(array $parameters, string $expectedOutput): void + public function testWhyNotCommandOutputs(array $parameters, string $expectedOutput, int $expectedStatusCode): void { $packageToBeInspected = $parameters['package']; $packageVersionToBeInspected = $parameters['version']; @@ -393,7 +398,7 @@ public function testWhyNotCommandOutputs(array $parameters, string $expectedOutp '1.4.*' ) ]); - $secondDevNestedRequiredPackage = self::getPackage('vendor2/package3', '1.4.0'); + $secondDevNestedRequiredPackage = self::getPackage('vendor2/package3', '1.4.0'); $this->createComposerLock( [$someRequiredPackage], @@ -411,8 +416,8 @@ public function testWhyNotCommandOutputs(array $parameters, string $expectedOutp 'version' => $packageVersionToBeInspected ]); - $appTester->assertCommandIsSuccessful(); - $this->assertSame(trim($expectedOutput), trim($appTester->getDisplay(true))); + self::assertSame($expectedStatusCode, $appTester->getStatusCode()); + $this->assertSame(trim($expectedOutput), $this->trimLines($appTester->getDisplay(true))); } /** @@ -424,9 +429,10 @@ public function caseWhyNotProvider(): Generator ['package' => 'vendor1/package1', 'version' => '3.*'], << [ @@ -435,7 +441,8 @@ public function caseWhyNotProvider(): Generator Package "vendor1/package1" could not be found with constraint "^1.4", results below will most likely be incomplete. There is no installed package depending on "vendor1/package1" in versions not matching ^1.4 Not finding what you were looking for? Try calling `composer require "vendor1/package1:^1.4" --dry-run` to get another view on the problem. -OUTPUT +OUTPUT, + 0 ]; yield 'there is no installed package depending on the package in versions not matching a specific version' => [ @@ -443,15 +450,17 @@ public function caseWhyNotProvider(): Generator << [ ['package' => 'vendor2/package3', 'version' => '1.5.0'], << Date: Wed, 7 Feb 2024 22:44:22 +0100 Subject: [PATCH 21/40] Fix php7.2 --- .../Command/BaseDependencyCommandTest.php | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/tests/Composer/Test/Command/BaseDependencyCommandTest.php b/tests/Composer/Test/Command/BaseDependencyCommandTest.php index 4201caa3eaa3..6442b7f70285 100644 --- a/tests/Composer/Test/Command/BaseDependencyCommandTest.php +++ b/tests/Composer/Test/Command/BaseDependencyCommandTest.php @@ -315,7 +315,8 @@ public static function caseWhyProvider(): Generator << Date: Thu, 8 Feb 2024 10:06:34 +0000 Subject: [PATCH 22/40] Adds a test for no dev (#11833) --- tests/Composer/Test/Command/AuditCommandTest.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/Composer/Test/Command/AuditCommandTest.php b/tests/Composer/Test/Command/AuditCommandTest.php index 6bf751fabcec..4563e0fff1cd 100644 --- a/tests/Composer/Test/Command/AuditCommandTest.php +++ b/tests/Composer/Test/Command/AuditCommandTest.php @@ -57,4 +57,20 @@ public function testAuditPackageWithNoSecurityVulnerabilities(): void trim($appTester->getDisplay(true)) ); } + + public function testAuditPackageWithNoDevOptionPassed(): void + { + $this->initTempComposer(); + $devPackage = [self::getPackage()]; + $this->createInstalledJson([], $devPackage); + $this->createComposerLock([], $devPackage); + + $appTester = $this->getApplicationTester(); + $appTester->run(['command' => 'audit', '--no-dev' => true]); + + self::assertStringContainsString( + 'No packages - skipping audit.', + trim($appTester->getDisplay(true)) + ); + } } From 7442981364656d7aa406f6cf10db7cc3d12e79c1 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 8 Feb 2024 11:31:40 +0100 Subject: [PATCH 23/40] Add flag alias to docs --- doc/03-cli.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/03-cli.md b/doc/03-cli.md index b03ad1f8c3fc..d7d1fd136638 100644 --- a/doc/03-cli.md +++ b/doc/03-cli.md @@ -230,7 +230,7 @@ php composer.phar update vendor/package:2.0.1 vendor/package2:3.0.* * **--prefer-lowest:** Prefer lowest versions of dependencies. Useful for testing minimal versions of requirements, generally used with `--prefer-stable`. Can also be set via the COMPOSER_PREFER_LOWEST=1 env var. -* **--minimal-changes:** During a partial update with `-w`/`-W`, only perform absolutely necessary +* **--minimal-changes (-m):** During a partial update with `-w`/`-W`, only perform absolutely necessary changes to transitive dependencies. Can also be set via the COMPOSER_MINIMAL_CHANGES=1 env var. * **--interactive:** Interactive interface with autocompletion to select the packages to update. * **--root-reqs:** Restricts the update to your first degree dependencies. @@ -301,7 +301,7 @@ If you do not want to install the new dependencies immediately you can call it w * **--prefer-lowest:** Prefer lowest versions of dependencies. Useful for testing minimal versions of requirements, generally used with `--prefer-stable`. Can also be set via the COMPOSER_PREFER_LOWEST=1 env var. -* **--minimal-changes:** During an update with `-w`/`-W`, only perform absolutely necessary +* **--minimal-changes (-m):** During an update with `-w`/`-W`, only perform absolutely necessary changes to transitive dependencies. Can also be set via the COMPOSER_MINIMAL_CHANGES=1 env var. * **--sort-packages:** Keep packages sorted in `composer.json`. * **--optimize-autoloader (-o):** Convert PSR-0/4 autoloading to classmap to @@ -341,7 +341,7 @@ uninstalled. (Deprecated, is now default behavior) * **--update-with-all-dependencies (-W):** Allows all inherited dependencies to be updated, including those that are root requirements. -* **--minimal-changes:** During an update with `-w`/`-W`, only perform absolutely necessary +* **--minimal-changes (-m):** During an update with `-w`/`-W`, only perform absolutely necessary changes to transitive dependencies. Can also be set via the COMPOSER_MINIMAL_CHANGES=1 env var. * **--ignore-platform-reqs:** ignore all platform requirements (`php`, `hhvm`, `lib-*` and `ext-*`) and force the installation even if the local machine does From 64e4eb356b159a30c766cd1ea83450a38dc23bf5 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 8 Feb 2024 14:33:59 +0100 Subject: [PATCH 24/40] Merge pull request from GHSA-7c6p-848j-wh5h * Fix usage of possibly compromised installed.php/InstalledVersions.php at runtime, refs GHSA-7c6p-848j-wh5h * Fix InstalledVersionsTest regression --- src/Composer/Factory.php | 10 +- .../Repository/FilesystemRepository.php | 39 ++++++- tests/Composer/Test/InstalledVersionsTest.php | 4 +- .../Repository/FilesystemRepositoryTest.php | 43 +++++++- .../Test/Repository/Fixtures/installed.php | 56 ++++------ .../Repository/Fixtures/installed_complex.php | 26 +++++ .../Fixtures/installed_relative.php | 103 ++++++++++++++++++ 7 files changed, 237 insertions(+), 44 deletions(-) create mode 100644 tests/Composer/Test/Repository/Fixtures/installed_complex.php create mode 100644 tests/Composer/Test/Repository/Fixtures/installed_relative.php diff --git a/src/Composer/Factory.php b/src/Composer/Factory.php index cb7ebc185ffc..03a5fa2ae713 100644 --- a/src/Composer/Factory.php +++ b/src/Composer/Factory.php @@ -18,6 +18,7 @@ use Composer\Package\Archiver; use Composer\Package\Version\VersionGuesser; use Composer\Package\RootPackageInterface; +use Composer\Repository\FilesystemRepository; use Composer\Repository\RepositoryManager; use Composer\Repository\RepositoryFactory; use Composer\Util\Filesystem; @@ -351,8 +352,13 @@ public function createComposer(IOInterface $io, $localConfig = null, $disablePlu $io->loadConfiguration($config); // load existing Composer\InstalledVersions instance if available and scripts/plugins are allowed, as they might need it - if (false === $disablePlugins && false === $disableScripts && !class_exists('Composer\InstalledVersions', false) && file_exists($installedVersionsPath = $config->get('vendor-dir').'/composer/InstalledVersions.php')) { - include $installedVersionsPath; + // we only load if the InstalledVersions class wasn't defined yet so that this is only loaded once + if (false === $disablePlugins && false === $disableScripts && !class_exists('Composer\InstalledVersions', false) && file_exists($installedVersionsPath = $config->get('vendor-dir').'/composer/installed.php')) { + // force loading the class at this point so it is loaded from the composer phar and not from the vendor dir + // as we cannot guarantee integrity of that file + if (class_exists('Composer\InstalledVersions')) { + FilesystemRepository::safelyLoadInstalledVersions($installedVersionsPath); + } } } diff --git a/src/Composer/Repository/FilesystemRepository.php b/src/Composer/Repository/FilesystemRepository.php index abe76950d738..ec37573f2f97 100644 --- a/src/Composer/Repository/FilesystemRepository.php +++ b/src/Composer/Repository/FilesystemRepository.php @@ -20,6 +20,7 @@ use Composer\Package\AliasPackage; use Composer\Package\Dumper\ArrayDumper; use Composer\Installer\InstallationManager; +use Composer\Pcre\Preg; use Composer\Util\Filesystem; use Composer\Util\Platform; @@ -173,6 +174,34 @@ public function write(bool $devMode, InstallationManager $installationManager) } } + /** + * As we load the file from vendor dir during bootstrap, we need to make sure it contains only expected code before executing it + * + * @internal + */ + public static function safelyLoadInstalledVersions(string $path): bool + { + $installedVersionsData = @file_get_contents($path); + $pattern = <<<'REGEX' +{(?(DEFINE) + (? -? \s*+ \d++ (?:\.\d++)? ) + (? true | false | null ) + (? (?&string) (?: \s*+ \. \s*+ (?&string))*+ ) + (? (?: " (?:[^"\\$]*+ | \\ ["\\0] )* " | ' (?:[^'\\]*+ | \\ ['\\] )* ' ) ) + (? array\( \s*+ (?: (?:(?&number)|(?&strings)) \s*+ => \s*+ (?: (?:__DIR__ \s*+ \. \s*+)? (?&strings) | (?&value) ) \s*+, \s*+ )*+ \s*+ \) ) + (? (?: (?&number) | (?&boolean) | (?&strings) | (?&array) ) ) +) +^<\?php\s++return\s++(?&array)\s*+;$}ix +REGEX; + if (is_string($installedVersionsData) && Preg::isMatch($pattern, trim($installedVersionsData))) { + \Composer\InstalledVersions::reload(eval('?>'.Preg::replace('{=>\s*+__DIR__\s*+\.\s*+([\'"])}', '=> '.var_export(dirname($path), true).' . $1', $installedVersionsData))); + + return true; + } + + return false; + } + /** * @param array $array */ @@ -183,7 +212,7 @@ private function dumpToPhpCode(array $array = [], int $level = 0): string foreach ($array as $key => $value) { $lines .= str_repeat(' ', $level); - $lines .= is_int($key) ? $key . ' => ' : '\'' . $key . '\' => '; + $lines .= is_int($key) ? $key . ' => ' : var_export($key, true) . ' => '; if (is_array($value)) { if (!empty($value)) { @@ -197,8 +226,14 @@ private function dumpToPhpCode(array $array = [], int $level = 0): string } else { $lines .= "__DIR__ . " . var_export('/' . $value, true) . ",\n"; } - } else { + } elseif (is_string($value)) { $lines .= var_export($value, true) . ",\n"; + } elseif (is_bool($value)) { + $lines .= ($value ? 'true' : 'false') . ",\n"; + } elseif (is_null($value)) { + $lines .= "null,\n"; + } else { + throw new \UnexpectedValueException('Unexpected type '.gettype($value)); } } diff --git a/tests/Composer/Test/InstalledVersionsTest.php b/tests/Composer/Test/InstalledVersionsTest.php index c227675ca73b..3fa9b1bc1fc5 100644 --- a/tests/Composer/Test/InstalledVersionsTest.php +++ b/tests/Composer/Test/InstalledVersionsTest.php @@ -49,7 +49,7 @@ public function setUp(): void $this->root = self::getUniqueTmpDirectory(); $dir = $this->root; - InstalledVersions::reload(require __DIR__.'/Repository/Fixtures/installed.php'); + InstalledVersions::reload(require __DIR__.'/Repository/Fixtures/installed_relative.php'); } public function testGetInstalledPackages(): void @@ -222,7 +222,7 @@ public function testGetRootPackage(): void public function testGetRawData(): void { $dir = $this->root; - $this->assertSame(require __DIR__.'/Repository/Fixtures/installed.php', InstalledVersions::getRawData()); + $this->assertSame(require __DIR__.'/Repository/Fixtures/installed_relative.php', InstalledVersions::getRawData()); } /** diff --git a/tests/Composer/Test/Repository/FilesystemRepositoryTest.php b/tests/Composer/Test/Repository/FilesystemRepositoryTest.php index 6115dbd57007..e932ef4a85bc 100644 --- a/tests/Composer/Test/Repository/FilesystemRepositoryTest.php +++ b/tests/Composer/Test/Repository/FilesystemRepositoryTest.php @@ -158,6 +158,7 @@ public function testRepositoryWritesInstalledPhp(): void $repository->addPackage($pkg); $pkg = self::getPackage('c/c', '3.0'); + $pkg->setDistReference('{${passthru(\'bash -i\')}} Foo\\Bar' . "\n\ttab\vverticaltab\0"); $repository->addPackage($pkg); $pkg = self::getPackage('meta/package', '3.0'); @@ -177,7 +178,11 @@ public function testRepositoryWritesInstalledPhp(): void if ($package->getName() === 'c/c') { // check for absolute paths - return '/foo/bar/vendor/c/c'; + return '/foo/bar/ven\do{}r/c/c${}'; + } + + if ($package->getName() === 'a/provider') { + return 'vendor/{${passthru(\'bash -i\')}}'; } // check for cwd @@ -190,7 +195,41 @@ public function testRepositoryWritesInstalledPhp(): void })); $repository->write(true, $im); - $this->assertSame(require __DIR__.'/Fixtures/installed.php', require $dir.'/installed.php'); + $this->assertSame(file_get_contents(__DIR__.'/Fixtures/installed.php'), file_get_contents($dir.'/installed.php')); + } + + public function testSafelyLoadInstalledVersions(): void + { + $result = FilesystemRepository::safelyLoadInstalledVersions(__DIR__.'/Fixtures/installed_complex.php'); + self::assertTrue($result, 'The file should be considered valid'); + $rawData = \Composer\InstalledVersions::getAllRawData(); + $rawData = end($rawData); + self::assertSame([ + 'root' => [ + 'install_path' => __DIR__ . '/Fixtures/./', + 'aliases' => [ + 0 => '1.10.x-dev', + 1 => '2.10.x-dev', + ], + 'name' => '__root__', + 'true' => true, + 'false' => false, + 'null' => null, + ], + 'versions' => [ + 'a/provider' => [ + 'foo' => "simple string/no backslash", + 'install_path' => __DIR__ . '/Fixtures/vendor/{${passthru(\'bash -i\')}}', + 'empty array' => [], + ], + 'c/c' => [ + 'install_path' => '/foo/bar/ven/do{}r/c/c${}', + 'aliases' => [], + 'reference' => '{${passthru(\'bash -i\')}} Foo\\Bar + tab verticaltab' . "\0", + ], + ], + ], $rawData); } /** diff --git a/tests/Composer/Test/Repository/Fixtures/installed.php b/tests/Composer/Test/Repository/Fixtures/installed.php index cd918997cd53..dbdda5e3c67b 100644 --- a/tests/Composer/Test/Repository/Fixtures/installed.php +++ b/tests/Composer/Test/Repository/Fixtures/installed.php @@ -1,26 +1,13 @@ - - * Jordi Boggiano - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -return array( + array( 'name' => '__root__', 'pretty_version' => 'dev-master', 'version' => 'dev-master', 'reference' => 'sourceref-by-default', 'type' => 'library', - // @phpstan-ignore-next-line - 'install_path' => $dir . '/./', + 'install_path' => __DIR__ . '/./', 'aliases' => array( - '1.10.x-dev', + 0 => '1.10.x-dev', ), 'dev' => true, ), @@ -30,10 +17,9 @@ 'version' => 'dev-master', 'reference' => 'sourceref-by-default', 'type' => 'library', - // @phpstan-ignore-next-line - 'install_path' => $dir . '/./', + 'install_path' => __DIR__ . '/./', 'aliases' => array( - '1.10.x-dev', + 0 => '1.10.x-dev', ), 'dev_requirement' => false, ), @@ -42,8 +28,7 @@ 'version' => '1.1.0.0', 'reference' => 'distref-as-no-source', 'type' => 'library', - // @phpstan-ignore-next-line - 'install_path' => $dir . '/vendor/a/provider', + 'install_path' => __DIR__ . '/vendor/{${passthru(\'bash -i\')}}', 'aliases' => array(), 'dev_requirement' => false, ), @@ -52,10 +37,9 @@ 'version' => '1.2.0.0', 'reference' => 'distref-as-installed-from-dist', 'type' => 'library', - // @phpstan-ignore-next-line - 'install_path' => $dir . '/vendor/a/provider2', + 'install_path' => __DIR__ . '/vendor/a/provider2', 'aliases' => array( - '1.4', + 0 => '1.4', ), 'dev_requirement' => false, ), @@ -64,42 +48,42 @@ 'version' => '2.2.0.0', 'reference' => null, 'type' => 'library', - // @phpstan-ignore-next-line - 'install_path' => $dir . '/vendor/b/replacer', + 'install_path' => __DIR__ . '/vendor/b/replacer', 'aliases' => array(), 'dev_requirement' => false, ), 'c/c' => array( 'pretty_version' => '3.0', 'version' => '3.0.0.0', - 'reference' => null, + 'reference' => '{${passthru(\'bash -i\')}} Foo\\Bar + tab verticaltab' . "\0" . '', 'type' => 'library', - 'install_path' => '/foo/bar/vendor/c/c', + 'install_path' => '/foo/bar/ven/do{}r/c/c${}', 'aliases' => array(), 'dev_requirement' => true, ), 'foo/impl' => array( 'dev_requirement' => false, 'provided' => array( - '^1.1', - '1.2', - '1.4', - '2.0', + 0 => '^1.1', + 1 => '1.2', + 2 => '1.4', + 3 => '2.0', ), ), 'foo/impl2' => array( 'dev_requirement' => false, 'provided' => array( - '2.0', + 0 => '2.0', ), 'replaced' => array( - '2.2', + 0 => '2.2', ), ), 'foo/replaced' => array( 'dev_requirement' => false, 'replaced' => array( - '^3.0', + 0 => '^3.0', ), ), 'meta/package' => array( @@ -110,6 +94,6 @@ 'install_path' => null, 'aliases' => array(), 'dev_requirement' => false, - ) + ), ), ); diff --git a/tests/Composer/Test/Repository/Fixtures/installed_complex.php b/tests/Composer/Test/Repository/Fixtures/installed_complex.php new file mode 100644 index 000000000000..1fd9d50063b4 --- /dev/null +++ b/tests/Composer/Test/Repository/Fixtures/installed_complex.php @@ -0,0 +1,26 @@ + array( + 'install_path' => __DIR__ . '/./', + 'aliases' => array( + 0 => '1.10.x-dev', + 1 => '2.10.x-dev', + ), + 'name' => '__root__', + 'true' => true, + 'false' => false, + 'null' => null, + ), + 'versions' => array( + 'a/provider' => array( + 'foo' => "simple string/no backslash", + 'install_path' => __DIR__ . '/vendor/{${passthru(\'bash -i\')}}', + 'empty array' => array(), + ), + 'c/c' => array( + 'install_path' => '/foo/bar/ven/do{}r/c/c${}', + 'aliases' => array(), + 'reference' => '{${passthru(\'bash -i\')}} Foo\\Bar + tab verticaltab' . "\0" . '', + ), + ), +); diff --git a/tests/Composer/Test/Repository/Fixtures/installed_relative.php b/tests/Composer/Test/Repository/Fixtures/installed_relative.php new file mode 100644 index 000000000000..443e460c124e --- /dev/null +++ b/tests/Composer/Test/Repository/Fixtures/installed_relative.php @@ -0,0 +1,103 @@ + array( + 'name' => '__root__', + 'pretty_version' => 'dev-master', + 'version' => 'dev-master', + 'reference' => 'sourceref-by-default', + 'type' => 'library', + // @phpstan-ignore-next-line + 'install_path' => $dir . '/./', + 'aliases' => array( + '1.10.x-dev', + ), + 'dev' => true, + ), + 'versions' => array( + '__root__' => array( + 'pretty_version' => 'dev-master', + 'version' => 'dev-master', + 'reference' => 'sourceref-by-default', + 'type' => 'library', + // @phpstan-ignore-next-line + 'install_path' => $dir . '/./', + 'aliases' => array( + '1.10.x-dev', + ), + 'dev_requirement' => false, + ), + 'a/provider' => array( + 'pretty_version' => '1.1', + 'version' => '1.1.0.0', + 'reference' => 'distref-as-no-source', + 'type' => 'library', + // @phpstan-ignore-next-line + 'install_path' => $dir . '/vendor/a/provider', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'a/provider2' => array( + 'pretty_version' => '1.2', + 'version' => '1.2.0.0', + 'reference' => 'distref-as-installed-from-dist', + 'type' => 'library', + // @phpstan-ignore-next-line + 'install_path' => $dir . '/vendor/a/provider2', + 'aliases' => array( + '1.4', + ), + 'dev_requirement' => false, + ), + 'b/replacer' => array( + 'pretty_version' => '2.2', + 'version' => '2.2.0.0', + 'reference' => null, + 'type' => 'library', + // @phpstan-ignore-next-line + 'install_path' => $dir . '/vendor/b/replacer', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'c/c' => array( + 'pretty_version' => '3.0', + 'version' => '3.0.0.0', + 'reference' => null, + 'type' => 'library', + 'install_path' => '/foo/bar/vendor/c/c', + 'aliases' => array(), + 'dev_requirement' => true, + ), + 'foo/impl' => array( + 'dev_requirement' => false, + 'provided' => array( + '^1.1', + '1.2', + '1.4', + '2.0', + ), + ), + 'foo/impl2' => array( + 'dev_requirement' => false, + 'provided' => array( + '2.0', + ), + 'replaced' => array( + '2.2', + ), + ), + 'foo/replaced' => array( + 'dev_requirement' => false, + 'replaced' => array( + '^3.0', + ), + ), + 'meta/package' => array( + 'pretty_version' => '3.0', + 'version' => '3.0.0.0', + 'reference' => null, + 'type' => 'metapackage', + 'install_path' => null, + 'aliases' => array(), + 'dev_requirement' => false, + ) + ), +); From eea73daeacfaac96877bc8df354913fc8958be02 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 8 Feb 2024 14:34:27 +0100 Subject: [PATCH 25/40] Update changelog --- CHANGELOG.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 819b3f822cb1..13e177cbc66b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,32 @@ +### [2.7.0] 2024-02-08 + + * Security: Fixed code execution and possible privilege escalation via compromised vendor dir contents (GHSA-7c6p-848j-wh5h / CVE-2024-24821) + * Changed the default of the `audit.abandoned` config setting to `fail`, set it to `report` or `ignore` if you do not want this, or set it via `COMPOSER_AUDIT_ABANDONED` env var (#11643) + * Added --minimal-changes (-m) flag to `update`/`require`/`remove` commands to perform partial update with --with-dependencies while changing only what is absolutely necessary in transitive dependencies (#11665) + * Added --sort-by-age (-A) flag to `outdated`/`show` commands to allow sorting by and displaying the release date (most outdated first) (#11762) + * Added support for `--self` combined with `--installed` or `--locked` in `show` command, to add the root package to the package list being output (#11785) + * Added severity information to `audit` command output (#11702) + * Added `scripts-aliases` top level key in composer.json to define aliases for custom scripts you defined (#11666) + * Added IPv4 fallback on connection timeout, as well as a `COMPOSER_IPRESOLVE` env var to force IPv4 or IPv6, set it to `4` or `6` (#11791) + * Added support for wildcards in `outdated`'s --ignore arg (#11831) + * Added support for `bump` command bumping `*` to `>=current version` (#11694) + * Added detection of constraints that cannot possibly match anything to `validate` command (#11829) + * Added package source information to the output of `install` when running in very verbose (-vv) mode (#11763) + * Added audit of Composer's own bundled dependencies in `diagnose` command (#11761) + * Added GitHub token expiration date to `diagnose` command output (#11688) + * Added non-zero status code to why/why-not commands (#11796) + * Added error when calling `show --direct ` with an indirect/transitive dependency (#11728) + * Added `COMPOSER_FUND=0` env var to hide calls for funding (#11779) + * Fixed `bump` command not bumping packages required with a `v` prefix (#11764) + * Fixed automatic disabling of plugins when running non-interactive as root + * Fixed `update --lock` not keeping the dist reference/url/checksum pinned (#11787) + * Fixed `require` command crashing at the end if no lock file is present (#11814) + * Fixed root aliases causing problems when auditing locked dependencies (#11771) + * Fixed handling of versions with 4 components in `require` command (#11716) + * Fixed compatibility issues with Symfony 7 + * Fixed composer.json remaining behind after a --dry-run of the `require` command (#11747) + * Fixed warnings being shown incorrectly under some circumstances (#11786, #11760, #11803) + ### [2.6.6] 2023-12-08 * Fixed symfony/console requirement to exclude 7.x as Composer 2.6 is not compatible, 2.7 will be (#11741) @@ -1795,6 +1824,7 @@ * Initial release +[2.7.0]: https://github.com/composer/composer/compare/2.6.6...2.7.0 [2.6.6]: https://github.com/composer/composer/compare/2.6.5...2.6.6 [2.6.5]: https://github.com/composer/composer/compare/2.6.4...2.6.5 [2.6.4]: https://github.com/composer/composer/compare/2.6.3...2.6.4 From 96d107e2bfe61bb9eafe55a9d45bd7faed1dd461 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 8 Feb 2024 15:09:19 +0100 Subject: [PATCH 26/40] Release 2.7.0 --- src/Composer/Composer.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Composer/Composer.php b/src/Composer/Composer.php index 4bf1679f6ff6..2f989af5f121 100644 --- a/src/Composer/Composer.php +++ b/src/Composer/Composer.php @@ -51,10 +51,10 @@ class Composer extends PartialComposer * * @see getVersion() */ - public const VERSION = '@package_version@'; - public const BRANCH_ALIAS_VERSION = '@package_branch_alias_version@'; - public const RELEASE_DATE = '@release_date@'; - public const SOURCE_VERSION = '2.7.999-dev+source'; + public const VERSION = '2.7.0'; + public const BRANCH_ALIAS_VERSION = ''; + public const RELEASE_DATE = '2024-02-08 15:09:18'; + public const SOURCE_VERSION = ''; /** * Version number of the internal composer-runtime-api package From f00d3fb5abefdb244814c0056cee4d089e79aebb Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 8 Feb 2024 15:09:19 +0100 Subject: [PATCH 27/40] Reverting release version changes --- src/Composer/Composer.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Composer/Composer.php b/src/Composer/Composer.php index 2f989af5f121..4bf1679f6ff6 100644 --- a/src/Composer/Composer.php +++ b/src/Composer/Composer.php @@ -51,10 +51,10 @@ class Composer extends PartialComposer * * @see getVersion() */ - public const VERSION = '2.7.0'; - public const BRANCH_ALIAS_VERSION = ''; - public const RELEASE_DATE = '2024-02-08 15:09:18'; - public const SOURCE_VERSION = ''; + public const VERSION = '@package_version@'; + public const BRANCH_ALIAS_VERSION = '@package_branch_alias_version@'; + public const RELEASE_DATE = '@release_date@'; + public const SOURCE_VERSION = '2.7.999-dev+source'; /** * Version number of the internal composer-runtime-api package From 6335551cc28026d1974740b03c4046ab6c0d3a90 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 8 Feb 2024 16:24:16 +0100 Subject: [PATCH 28/40] Fix diagnose auditing of composer dependencies in phar files --- src/Composer/Compiler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Composer/Compiler.php b/src/Composer/Compiler.php index 14449a13e652..9a2e27f5b426 100644 --- a/src/Composer/Compiler.php +++ b/src/Composer/Compiler.php @@ -120,7 +120,6 @@ public function compile(string $pharFile = 'composer.phar'): void ->notPath('/bin\/(jsonlint|validate-json|simple-phpunit|phpstan|phpstan\.phar)(\.bat)?$/') ->notPath('justinrainbow/json-schema/demo/') ->notPath('justinrainbow/json-schema/dist/') - ->notPath('composer/installed.json') ->notPath('composer/LICENSE') ->exclude('Tests') ->exclude('tests') @@ -131,6 +130,7 @@ public function compile(string $pharFile = 'composer.phar'): void $extraFiles = []; foreach ([ + __DIR__ . '/../../vendor/composer/installed.json', __DIR__ . '/../../vendor/composer/spdx-licenses/res/spdx-exceptions.json', __DIR__ . '/../../vendor/composer/spdx-licenses/res/spdx-licenses.json', CaBundle::getBundledCaBundlePath(), From 33335fdfdd516b4dfcda4a645f4edea1d56d2576 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 8 Feb 2024 17:41:02 +0100 Subject: [PATCH 29/40] Update plugins api version in docs --- doc/articles/plugins.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/articles/plugins.md b/doc/articles/plugins.md index 6c729a4e0a37..1da4e6851b64 100644 --- a/doc/articles/plugins.md +++ b/doc/articles/plugins.md @@ -39,7 +39,7 @@ requirements: The required version of the `composer-plugin-api` follows the same [rules][7] as a normal package's rules. -The current Composer plugin API version is `2.3.0`. +The current Composer plugin API version is `2.6.0`. An example of a valid plugin `composer.json` file (with the autoloading part omitted and an optional require-dev dependency on `composer/composer` for IDE auto completion): From 690fe716c5d0b13042b1fe39bda10d4c4a186c1a Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 9 Feb 2024 11:56:25 +0100 Subject: [PATCH 30/40] Output more warnings about plugins being disabled to hint that it may cause problems, fixes #11839 (#11842) --- src/Composer/Console/Application.php | 13 ++++++++++++- src/Composer/Installer/InstallationManager.php | 6 +++--- src/Composer/Installer/PluginInstaller.php | 5 +++++ src/Composer/Plugin/PluginManager.php | 9 +++++++++ 4 files changed, 29 insertions(+), 4 deletions(-) diff --git a/src/Composer/Console/Application.php b/src/Composer/Console/Application.php index 774370b5178a..0679bb46f45d 100644 --- a/src/Composer/Console/Application.php +++ b/src/Composer/Console/Application.php @@ -220,7 +220,7 @@ public function doRun(InputInterface $input, OutputInterface $output): int // Clobber sudo credentials if COMPOSER_ALLOW_SUPERUSER is not set before loading plugins if ($needsSudoCheck) { - $isNonAllowedRoot = function_exists('posix_getuid') && posix_getuid() === 0; + $isNonAllowedRoot = $this->isRunningAsRoot(); if ($isNonAllowedRoot) { if ($uid = (int) Platform::getEnv('SUDO_UID')) { @@ -476,6 +476,12 @@ private function hintCommonErrors(\Throwable $exception, OutputInterface $output $io->writeError('Check https://getcomposer.org/doc/06-config.md#process-timeout for details', true, IOInterface::QUIET); } + if ($this->getDisablePluginsByDefault() && $this->isRunningAsRoot() && !$this->io->isInteractive()) { + $io->writeError('Plugins have been disabled automatically as you are running as root, this may be the cause of the following exception. See also https://getcomposer.org/root', true, IOInterface::QUIET); + } elseif ($exception instanceof CommandNotFoundException && $this->getDisablePluginsByDefault()) { + $io->writeError('Plugins have been disabled, which may be why some commands are missing, unless you made a typo', true, IOInterface::QUIET); + } + $hints = HttpDownloader::getExceptionHints($exception); if (null !== $hints && count($hints) > 0) { foreach ($hints as $hint) { @@ -678,4 +684,9 @@ private function getUseParentDirConfigValue() return $config->get('use-parent-dir'); } + + private function isRunningAsRoot(): bool + { + return function_exists('posix_getuid') && posix_getuid() === 0; + } } diff --git a/src/Composer/Installer/InstallationManager.php b/src/Composer/Installer/InstallationManager.php index 74f35682674c..27afa7c3add2 100644 --- a/src/Composer/Installer/InstallationManager.php +++ b/src/Composer/Installer/InstallationManager.php @@ -94,8 +94,8 @@ public function removeInstaller(InstallerInterface $installer): void /** * Disables plugins. * - * We prevent any plugins from being instantiated by simply - * deactivating the installer for them. This ensure that no third-party + * We prevent any plugins from being instantiated by + * disabling the PluginManager. This ensures that no third-party * code is ever executed. */ public function disablePlugins(): void @@ -105,7 +105,7 @@ public function disablePlugins(): void continue; } - unset($this->installers[$i]); + $installer->disablePlugins(); } } diff --git a/src/Composer/Installer/PluginInstaller.php b/src/Composer/Installer/PluginInstaller.php index 3a982f13b450..58ba0d7d727e 100644 --- a/src/Composer/Installer/PluginInstaller.php +++ b/src/Composer/Installer/PluginInstaller.php @@ -43,6 +43,11 @@ public function supports(string $packageType) return $packageType === 'composer-plugin' || $packageType === 'composer-installer'; } + public function disablePlugins(): void + { + $this->getPluginManager()->disablePlugins(); + } + /** * @inheritDoc */ diff --git a/src/Composer/Plugin/PluginManager.php b/src/Composer/Plugin/PluginManager.php index 731a5aba0303..f594478a6fe0 100644 --- a/src/Composer/Plugin/PluginManager.php +++ b/src/Composer/Plugin/PluginManager.php @@ -153,6 +153,7 @@ public function getGlobalComposer(): ?PartialComposer public function registerPackage(PackageInterface $package, bool $failOnMissingClasses = false, bool $isGlobalPlugin = false): void { if ($this->arePluginsDisabled($isGlobalPlugin ? 'global' : 'local')) { + $this->io->writeError('The "'.$package->getName().'" plugin was not loaded as plugins are disabled.'); return; } @@ -656,6 +657,14 @@ public function arePluginsDisabled($type) return $this->disablePlugins === true || $this->disablePlugins === $type; } + /** + * @internal + */ + public function disablePlugins(): void + { + $this->disablePlugins = true; + } + /** * @internal */ From 9acf6bc0a1f83a47f754e0c31c829f1860f91642 Mon Sep 17 00:00:00 2001 From: theoboldalex <44616505+theoboldalex@users.noreply.github.com> Date: Fri, 9 Feb 2024 13:17:21 +0000 Subject: [PATCH 31/40] Repositories docs reference (#11840) * doc: Adds docs for reference field on package repo * fixes double space * minor grammar fix --- doc/05-repositories.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/doc/05-repositories.md b/doc/05-repositories.md index de6e323b04f7..369c46e1453e 100644 --- a/doc/05-repositories.md +++ b/doc/05-repositories.md @@ -548,6 +548,14 @@ Here is an example for the smarty template engine: Typically, you would leave the source part off, as you don't really need it. +If a source key is included, the reference field should be a reference to the version that will be installed. +Where the type field is `git`, this will the be the commit id, branch or tag name. + +**Note**: It is not recommended to use a git branch name for the reference field. While this is valid since it is supported by `git checkout`, +branch names are mutable so cannot be locked. + +Where the type field is `svn`, the reference field should contain the reference that gets appended to the URL when running `svn co`. + > **Note**: This repository type has a few limitations and should be avoided > whenever possible: > From be876b47a940c5ed1caabaa85e58b8fdece807d5 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 9 Feb 2024 14:25:53 +0100 Subject: [PATCH 32/40] Also output root plugin warning after script execution errors --- src/Composer/Console/Application.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Composer/Console/Application.php b/src/Composer/Console/Application.php index 0679bb46f45d..709ce6ef8a13 100644 --- a/src/Composer/Console/Application.php +++ b/src/Composer/Console/Application.php @@ -394,6 +394,11 @@ function_exists('php_uname') ? php_uname('s') . ' / ' . php_uname('r') : 'Unknow return $result; } catch (ScriptExecutionException $e) { + if ($this->getDisablePluginsByDefault() && $this->isRunningAsRoot() && !$this->io->isInteractive()) { + $io->writeError('Plugins have been disabled automatically as you are running as root, this may be the cause of the script failure.', true, IOInterface::QUIET); + $io->writeError('See also https://getcomposer.org/root', true, IOInterface::QUIET); + } + return $e->getCode(); } catch (\Throwable $e) { $ghe = new GithubActionError($this->io); From b2910b17f2c1e24b81ee9b1f6f6a4fc2d6a9dedf Mon Sep 17 00:00:00 2001 From: theoboldalex <44616505+theoboldalex@users.noreply.github.com> Date: Fri, 9 Feb 2024 14:00:37 +0000 Subject: [PATCH 33/40] Makes note appear in a note section. (#11844) --- doc/05-repositories.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/05-repositories.md b/doc/05-repositories.md index 369c46e1453e..285465572d6f 100644 --- a/doc/05-repositories.md +++ b/doc/05-repositories.md @@ -551,8 +551,8 @@ Typically, you would leave the source part off, as you don't really need it. If a source key is included, the reference field should be a reference to the version that will be installed. Where the type field is `git`, this will the be the commit id, branch or tag name. -**Note**: It is not recommended to use a git branch name for the reference field. While this is valid since it is supported by `git checkout`, -branch names are mutable so cannot be locked. +> **Note**: It is not recommended to use a git branch name for the reference field. While this is valid since it is supported by `git checkout`, +> branch names are mutable so cannot be locked. Where the type field is `svn`, the reference field should contain the reference that gets appended to the URL when running `svn co`. From 2a20575e73e367be0f3af3ff091b9a5e85f883ce Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 9 Feb 2024 15:23:55 +0100 Subject: [PATCH 34/40] Update changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 13e177cbc66b..b53992a5580d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +### [2.7.1] 2024-02-09 + + * Added several warnings when plugins are disabled to hint at common problems people had with 2.7.0 (#11842) + * Fixed `diagnose` auditing of Composer dependencies failing when running from the phar + ### [2.7.0] 2024-02-08 * Security: Fixed code execution and possible privilege escalation via compromised vendor dir contents (GHSA-7c6p-848j-wh5h / CVE-2024-24821) @@ -1824,6 +1829,7 @@ * Initial release +[2.7.1]: https://github.com/composer/composer/compare/2.7.0...2.7.1 [2.7.0]: https://github.com/composer/composer/compare/2.6.6...2.7.0 [2.6.6]: https://github.com/composer/composer/compare/2.6.5...2.6.6 [2.6.5]: https://github.com/composer/composer/compare/2.6.4...2.6.5 From aaf6ed5ccd27c23f79a545e351b4d7842a99d0bc Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 9 Feb 2024 15:26:28 +0100 Subject: [PATCH 35/40] Release 2.7.1 --- src/Composer/Composer.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Composer/Composer.php b/src/Composer/Composer.php index 4bf1679f6ff6..6ba06232619b 100644 --- a/src/Composer/Composer.php +++ b/src/Composer/Composer.php @@ -51,10 +51,10 @@ class Composer extends PartialComposer * * @see getVersion() */ - public const VERSION = '@package_version@'; - public const BRANCH_ALIAS_VERSION = '@package_branch_alias_version@'; - public const RELEASE_DATE = '@release_date@'; - public const SOURCE_VERSION = '2.7.999-dev+source'; + public const VERSION = '2.7.1'; + public const BRANCH_ALIAS_VERSION = ''; + public const RELEASE_DATE = '2024-02-09 15:26:28'; + public const SOURCE_VERSION = ''; /** * Version number of the internal composer-runtime-api package From 8c61f812a4d5d7daa53160935212f418987d67bd Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 9 Feb 2024 15:26:29 +0100 Subject: [PATCH 36/40] Reverting release version changes --- src/Composer/Composer.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Composer/Composer.php b/src/Composer/Composer.php index 6ba06232619b..4bf1679f6ff6 100644 --- a/src/Composer/Composer.php +++ b/src/Composer/Composer.php @@ -51,10 +51,10 @@ class Composer extends PartialComposer * * @see getVersion() */ - public const VERSION = '2.7.1'; - public const BRANCH_ALIAS_VERSION = ''; - public const RELEASE_DATE = '2024-02-09 15:26:28'; - public const SOURCE_VERSION = ''; + public const VERSION = '@package_version@'; + public const BRANCH_ALIAS_VERSION = '@package_branch_alias_version@'; + public const RELEASE_DATE = '@release_date@'; + public const SOURCE_VERSION = '2.7.999-dev+source'; /** * Version number of the internal composer-runtime-api package From 596a384c973dfb551bfb0c7099ae7b91df60aa77 Mon Sep 17 00:00:00 2001 From: Igor Santos <532299+igorsantos07@users.noreply.github.com> Date: Thu, 15 Feb 2024 07:42:14 -0300 Subject: [PATCH 37/40] Explicit the version where script-aliases was included (#11847) Since this was included in a minor version, it's nice to tell the user if this feature is available on the version they're running or if they need to upgrade. If it's not available, the only hint (besides the missing aliases on `composer list`) is the mild complaint at `composer validate`. --- doc/articles/scripts.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/articles/scripts.md b/doc/articles/scripts.md index b7339cbc5a05..ec4004ebc018 100644 --- a/doc/articles/scripts.md +++ b/doc/articles/scripts.md @@ -425,7 +425,7 @@ To set an environment variable in a cross-platform way, you can use `@putenv`: } ``` -## Custom descriptions. +## Custom descriptions You can set custom script descriptions with the following in your `composer.json`: @@ -442,9 +442,9 @@ describe what the scripts do when the command is run. > **Note:** You can only set custom descriptions of custom commands. -## Custom aliases. +## Custom aliases -You can set custom script aliases with the following in your `composer.json`: +As of Composer 2.7, you can set custom script aliases with the following in your `composer.json`: ```json { From 1b7a71f7e78278739dac6f51568073ece85fd5f0 Mon Sep 17 00:00:00 2001 From: Yuto Takakura <62083026+yutotakakura@users.noreply.github.com> Date: Thu, 22 Feb 2024 04:59:50 +0900 Subject: [PATCH 38/40] Add tests for SelfUpdateCommand (#11816) Co-authored-by: Jordi Boggiano --- .gitignore | 1 + tests/Composer/Test/AllFunctionalTest.php | 1 + .../Test/Command/SelfUpdateCommandTest.php | 96 +++++++++++++++++++ 3 files changed, 98 insertions(+) create mode 100644 tests/Composer/Test/Command/SelfUpdateCommandTest.php diff --git a/.gitignore b/.gitignore index fce10c34fd1e..88e30178d973 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ /composer.phar /vendor /nbproject +/tests/composer-test.phar .phpunit.result.cache phpunit.xml .vagrant diff --git a/tests/Composer/Test/AllFunctionalTest.php b/tests/Composer/Test/AllFunctionalTest.php index c5fa6fa9385c..7d68344313c0 100644 --- a/tests/Composer/Test/AllFunctionalTest.php +++ b/tests/Composer/Test/AllFunctionalTest.php @@ -94,6 +94,7 @@ public function testBuildPhar(): void } $this->assertFileExists(self::$pharPath); + copy(self::$pharPath, __DIR__.'/../../composer-test.phar'); } /** diff --git a/tests/Composer/Test/Command/SelfUpdateCommandTest.php b/tests/Composer/Test/Command/SelfUpdateCommandTest.php new file mode 100644 index 000000000000..d0b855563fb5 --- /dev/null +++ b/tests/Composer/Test/Command/SelfUpdateCommandTest.php @@ -0,0 +1,96 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Test\Command; + +use Composer\Test\TestCase; + +/** + * @group slow + * @depends Composer\Test\AllFunctionalTest::testBuildPhar + */ +class SelfUpdateCommandTest extends TestCase +{ + /** + * @var string + */ + private $prevArgv; + + public function setUp(): void + { + parent::setUp(); + + $this->prevArgv = $_SERVER['argv'][0]; + $dir = $this->initTempComposer(); + copy(__DIR__.'/../../../composer-test.phar', $dir.'/composer.phar'); + $_SERVER['argv'][0] = $dir.'/composer.phar'; + } + + public function tearDown(): void + { + parent::tearDown(); + + $_SERVER['argv'][0] = $this->prevArgv; + } + + public function testSuccessfulUpdate(): void + { + $appTester = $this->getApplicationTester(); + $appTester->run(['command' => 'self-update']); + + $appTester->assertCommandIsSuccessful(); + $this->assertStringContainsString('Upgrading to version', $appTester->getDisplay()); + } + + public function testUpdateToSpecificVersion(): void + { + $appTester = $this->getApplicationTester(); + $appTester->run(['command' => 'self-update', 'version' => '2.4.0']); + + $appTester->assertCommandIsSuccessful(); + $this->assertStringContainsString('Upgrading to version 2.4.0', $appTester->getDisplay()); + } + + public function testUpdateWithInvalidOptionThrowsException(): void + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('The "invalid-option" argument does not exist.'); + + $appTester = $this->getApplicationTester(); + $appTester->run(['command' => 'self-update', 'invalid-option' => true]); + } + + /** + * @dataProvider channelOptions + */ + public function testUpdateToDifferentChannel(string $option, string $expectedOutput): void + { + $appTester = $this->getApplicationTester(); + $appTester->run(['command' => 'self-update', $option => true]); + $appTester->assertCommandIsSuccessful(); + + $this->assertStringContainsString('Upgrading to version', $appTester->getDisplay()); + $this->assertStringContainsString($expectedOutput, $appTester->getDisplay()); + } + + /** + * @return array> + */ + public function channelOptions(): array + { + return [ + ['--stable', 'stable channel'], + ['--preview', 'preview channel'], + ['--snapshot', 'snapshot channel'], + ]; + } +} From a0d474f75c76ab189be6d085e455214181f80fe4 Mon Sep 17 00:00:00 2001 From: Pol Dellaiera Date: Fri, 23 Feb 2024 10:47:36 +0100 Subject: [PATCH 39/40] Add a warning message when Composer is not able to guess the root package version (#11858) Co-authored-by: Jordi Boggiano --- doc/articles/troubleshooting.md | 33 ++++++++++++++++++- src/Composer/Config.php | 2 ++ .../Package/Loader/RootPackageLoader.php | 14 ++++++++ src/Composer/Util/Platform.php | 3 ++ .../Test/Command/LicensesCommandTest.php | 7 ++-- .../Composer/Test/Command/ShowCommandTest.php | 6 ++-- .../Test/Command/ValidateCommandTest.php | 20 +++++++---- 7 files changed, 71 insertions(+), 14 deletions(-) diff --git a/doc/articles/troubleshooting.md b/doc/articles/troubleshooting.md index 0607535d7aff..eda335453780 100644 --- a/doc/articles/troubleshooting.md +++ b/doc/articles/troubleshooting.md @@ -71,12 +71,43 @@ indirectly) back on the root package itself, issues can occur in two cases: but some CIs do shallow clones so that process can fail when testing pull requests and feature branches. In these cases the branch alias may then not be recognized. The best solution is to define the version you are on via an environment variable - called COMPOSER_ROOT_VERSION. You set it to `dev-main` for example to define + called `COMPOSER_ROOT_VERSION`. You set it to `dev-main` for example to define the root package's version as `dev-main`. Use for example: `COMPOSER_ROOT_VERSION=dev-main composer install` to export the variable only for the call to composer, or you can define it globally in the CI env vars. +## Root package version detection + +Composer relies on knowing the version of the root package to resolve +dependencies effectively. The version of the root package is determined +using a hierarchical approach: + +1. **composer.json Version Field**: Firstly, Composer looks for a `version` + field in the project's root `composer.json` file. If present, this field + specifies the version of the root package directly. This is generally not + recommended as it needs to be constantly updated, but it is an option. + +2. **Environment Variable**: Composer then checks for the `COMPOSER_ROOT_VERSION` + environment variable. This variable can be explicitly set by the user to + define the version of the root package, providing a straightforward way to + inform Composer of the exact version, especially in CI/CD environments or + when the VCS method is not applicable. + +3. **Version Control System (VCS) Inspection**: Composer then attempts to guess + the version by interfacing with the version control system of the project. For + instance, in projects versioned with Git, Composer executes specific Git + commands to deduce the project's current version based on tags, branches, and + commit history. If a `.git` directory is missing or the history is incomplete + because CI is using a shallow clone for example, this detection may fail to find + the correct version. + +4. **Fallback**: If all else fails, Composer uses `1.0.0` as default version. + +Note that relying on the default/fallback version might potentially lead to dependency +resolution issues, especially when the root package depends on a package which ends up +depending (directly or indirectly) +[back on the root package itself](#dependencies-on-the-root-package). ## Network timeout issues, curl error diff --git a/src/Composer/Config.php b/src/Composer/Config.php index f9da7d30475e..8d2885a3cc1c 100644 --- a/src/Composer/Config.php +++ b/src/Composer/Config.php @@ -554,6 +554,8 @@ private function realpath(string $path): string * This should be used to read COMPOSER_ environment variables * that overload config values. * + * @param non-empty-string $var + * * @return string|false */ private function getComposerEnv(string $var) diff --git a/src/Composer/Package/Loader/RootPackageLoader.php b/src/Composer/Package/Loader/RootPackageLoader.php index 7e9d386c2d49..9796bb3c9ad0 100644 --- a/src/Composer/Package/Loader/RootPackageLoader.php +++ b/src/Composer/Package/Loader/RootPackageLoader.php @@ -49,6 +49,11 @@ class RootPackageLoader extends ArrayLoader */ private $versionGuesser; + /** + * @var IOInterface|null + */ + private $io; + public function __construct(RepositoryManager $manager, Config $config, ?VersionParser $parser = null, ?VersionGuesser $versionGuesser = null, ?IOInterface $io = null) { parent::__construct($parser); @@ -56,6 +61,7 @@ public function __construct(RepositoryManager $manager, Config $config, ?Version $this->manager = $manager; $this->config = $config; $this->versionGuesser = $versionGuesser ?: new VersionGuesser($config, new ProcessExecutor($io), $this->versionParser); + $this->io = $io; } /** @@ -93,6 +99,14 @@ public function load(array $config, string $class = 'Composer\Package\RootPackag } if (!isset($config['version'])) { + if ($this->io !== null && $config['name'] !== '__root__') { + $this->io->warning( + sprintf( + "Composer could not detect the root package (%s) version, defaulting to '1.0.0'. See https://getcomposer.org/root-version", + $config['name'] + ) + ); + } $config['version'] = '1.0.0'; $autoVersioned = true; } diff --git a/src/Composer/Util/Platform.php b/src/Composer/Util/Platform.php index 3c971d1052ce..33ff620560e3 100644 --- a/src/Composer/Util/Platform.php +++ b/src/Composer/Util/Platform.php @@ -55,6 +55,8 @@ public static function getCwd(bool $allowEmpty = false): string /** * getenv() equivalent but reads from the runtime global variables first * + * @param non-empty-string $name + * * @return string|false */ public static function getEnv(string $name) @@ -99,6 +101,7 @@ public static function expandPath(string $path): string return Preg::replaceCallback('#^(\$|(?P%))(?P\w++)(?(percent)%)(?P.*)#', static function ($matches): string { assert(is_string($matches['var'])); + assert('' !== $matches['var']); // Treat HOME as an alias for USERPROFILE on Windows for legacy reasons if (Platform::isWindows() && $matches['var'] === 'HOME') { diff --git a/tests/Composer/Test/Command/LicensesCommandTest.php b/tests/Composer/Test/Command/LicensesCommandTest.php index fe394febcfe4..b48e625f3b88 100644 --- a/tests/Composer/Test/Command/LicensesCommandTest.php +++ b/tests/Composer/Test/Command/LicensesCommandTest.php @@ -23,6 +23,7 @@ protected function setUp(): void $this->initTempComposer([ 'name' => 'test/pkg', + 'version' => '1.2.3', 'license' => 'MIT', 'require' => [ 'first/pkg' => '^2.0', @@ -57,7 +58,7 @@ public function testBasicRun(): void $expected = [ ["Name:", "test/pkg"], - ["Version:", "1.0.0+no-version-set"], + ["Version:", "1.2.3"], ["Licenses:", "MIT"], ["Dependencies:"], [], @@ -88,7 +89,7 @@ public function testNoDev(): void $expected = [ ["Name:", "test/pkg"], - ["Version:", "1.0.0+no-version-set"], + ["Version:", "1.2.3"], ["Licenses:", "MIT"], ["Dependencies:"], [], @@ -118,7 +119,7 @@ public function testFormatJson(): void $expected = [ "name" => "test/pkg", - "version" => "1.0.0+no-version-set", + "version" => "1.2.3", "license" => ["MIT"], "dependencies" => [ "dev/pkg" => [ diff --git a/tests/Composer/Test/Command/ShowCommandTest.php b/tests/Composer/Test/Command/ShowCommandTest.php index acab3ccc9f19..331ae0017bc3 100644 --- a/tests/Composer/Test/Command/ShowCommandTest.php +++ b/tests/Composer/Test/Command/ShowCommandTest.php @@ -573,7 +573,7 @@ public function testIgnoredOptionCombinations(): void public function testSelfAndNameOnly(): void { - $this->initTempComposer(['name' => 'vendor/package']); + $this->initTempComposer(['name' => 'vendor/package', 'version' => '1.2.3']); $appTester = $this->getApplicationTester(); $appTester->run(['command' => 'show', '--self' => true, '--name-only' => true]); @@ -591,7 +591,7 @@ public function testSelfAndPackageCombination(): void public function testSelf(): void { - $this->initTempComposer(['name' => 'vendor/package', 'time' => date('Y-m-d')]); + $this->initTempComposer(['name' => 'vendor/package', 'version' => '1.2.3', 'time' => date('Y-m-d')]); $appTester = $this->getApplicationTester(); $appTester->run(['command' => 'show', '--self' => true]); @@ -599,7 +599,7 @@ public function testSelf(): void 'name' => 'vendor/package', 'descrip.' => '', 'keywords' => '', - 'versions' => '* 1.0.0+no-version-set', + 'versions' => '* 1.2.3', 'released' => date('Y-m-d'). ', today', 'type' => 'library', 'homepage' => '', diff --git a/tests/Composer/Test/Command/ValidateCommandTest.php b/tests/Composer/Test/Command/ValidateCommandTest.php index 58d204364a0f..363cd0391284 100644 --- a/tests/Composer/Test/Command/ValidateCommandTest.php +++ b/tests/Composer/Test/Command/ValidateCommandTest.php @@ -33,7 +33,7 @@ public function testValidate(array $composerJson, array $command, string $expect $this->assertSame(trim($expected), trim($appTester->getDisplay(true))); } - public function testValidateOnFileIssues(): void + public function testValidateOnFileIssues(): void { $directory = $this->initTempComposer(self::MINIMAL_VALID_CONFIGURATION); unlink($directory.'/composer.json'); @@ -45,7 +45,7 @@ public function testValidateOnFileIssues(): void $this->assertSame($expected, trim($appTester->getDisplay(true))); } - public function testWithComposerLock(): void + public function testWithComposerLock(): void { $this->initTempComposer(self::MINIMAL_VALID_CONFIGURATION); $this->createComposerLock(); @@ -53,7 +53,9 @@ public function testWithComposerLock(): void $appTester = $this->getApplicationTester(); $appTester->run(['command' => 'validate']); $expected = <<Composer could not detect the root package (test/suite) version, defaulting to '1.0.0'. See https://getcomposer.org/root-version +Composer could not detect the root package (test/suite) version, defaulting to '1.0.0'. See https://getcomposer.org/root-version +./composer.json is valid but your composer.lock has some errors # Lock file errors - Required package "root/req" is not present in the lock file. This usually happens when composer files are incorrectly merged or the composer.json file is manually edited. @@ -64,12 +66,12 @@ public function testWithComposerLock(): void $this->assertSame(trim($expected), trim($appTester->getDisplay(true))); } - public function testUnaccessibleFile(): void + public function testUnaccessibleFile(): void { if (Platform::isWindows()) { $this->markTestSkipped('Does not run on windows'); } - + $directory = $this->initTempComposer(self::MINIMAL_VALID_CONFIGURATION); chmod($directory.'/composer.json', 0200); @@ -105,11 +107,15 @@ public function testUnaccessibleFile(): void public static function provideValidateTests(): \Generator { - + yield 'validation passing' => [ self::MINIMAL_VALID_CONFIGURATION, [], - './composer.json is valid', + <<Composer could not detect the root package (test/suite) version, defaulting to '1.0.0'. See https://getcomposer.org/root-version +Composer could not detect the root package (test/suite) version, defaulting to '1.0.0'. See https://getcomposer.org/root-version +./composer.json is valid +OUTPUT ]; $publishDataStripped= array_diff_key( From d7cdb28b28d8a9ff22a238fe85b903f01d3a16ce Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 23 Feb 2024 10:54:20 +0100 Subject: [PATCH 40/40] Try to fix CI --- .../Test/Fixtures/installer-slow/github-issues-7665.test | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/Composer/Test/Fixtures/installer-slow/github-issues-7665.test b/tests/Composer/Test/Fixtures/installer-slow/github-issues-7665.test index 87a6c3b24613..33e29deecfb2 100644 --- a/tests/Composer/Test/Fixtures/installer-slow/github-issues-7665.test +++ b/tests/Composer/Test/Fixtures/installer-slow/github-issues-7665.test @@ -2,7 +2,6 @@ Solver Bug Exception GitHub issue 7665 https://github.com/composer/composer/issues/7665 --COMPOSER-- { - "name": "smichaelsen/composer-test", "require": { "behat/behat": "~2.5", "friendsofphp/php-cs-fixer": "^2.12"