feat: add ability to skip package.json synchronization

by @wuchen90

Some issues have been detected in this pull request

Issues that can be fixed by applying a patch

Review the proposed patch then download it to apply it manually or execute the following command from the repository root directory:

curl https://fabbot.io/patch/symfony/flex/1032/6a726fa9cdb66fd66e9e0d6189e8992218ec9330/cs.diff | patch -p0
diff -ru src/Command/RecipesCommand.php src/Command/RecipesCommand.php
--- src/Command/RecipesCommand.php	2025-03-03 07:50:22.929990390 +0000
+++ src/Command/RecipesCommand.php	2025-03-03 07:50:26.703997124 +0000
@@ -81,7 +81,7 @@
                 $pkgVersion = $this->symfonyLock->get($name)['version'];
                 $pkg = new Package($name, $pkgVersion, $pkgVersion);
             } elseif (!$pkg) {
-                $this->getIO()->writeError(sprintf('<error>Package %s is not installed</error>', $name));
+                $this->getIO()->writeError(\sprintf('<error>Package %s is not installed</error>', $name));
 
                 continue;
             }
@@ -125,7 +125,7 @@
             }
 
             $hasOutdatedRecipes = true;
-            $write[] = sprintf(' * %s %s', $name, $additional);
+            $write[] = \sprintf(' * %s %s', $name, $additional);
         }
 
         // Nothing to display
@@ -136,7 +136,7 @@
         $this->getIO()->write(array_merge([
             '',
             '<bg=blue;fg=white>                      </>',
-            sprintf('<bg=blue;fg=white> %s recipes.   </>', $outdated ? ' Outdated' : 'Available'),
+            \sprintf('<bg=blue;fg=white> %s recipes.   </>', $outdated ? ' Outdated' : 'Available'),
             '<bg=blue;fg=white>                      </>',
             '',
         ], $write, [
@@ -200,7 +200,7 @@
         $io->write('<info>version</info>          : '.($lockVersion ?? 'n/a'));
         $io->write('<info>status</info>           : '.$status);
         if (!$recipe->isAuto() && null !== $lockVersion) {
-            $recipeUrl = sprintf(
+            $recipeUrl = \sprintf(
                 'https://%s/tree/%s/%s/%s',
                 $lockRepo,
                 // if something fails, default to the branch as the closest "sha"
@@ -217,7 +217,7 @@
         }
 
         if ($lockRef !== $recipe->getRef() && null !== $lockVersion) {
-            $historyUrl = sprintf(
+            $historyUrl = \sprintf(
                 'https://%s/commits/%s/%s',
                 $lockRepo,
                 $lockBranch,
@@ -249,7 +249,7 @@
             $io->write([
                 '',
                 'Update this recipe by running:',
-                sprintf('<info>composer recipes:update %s</info>', $recipe->getName()),
+                \sprintf('<info>composer recipes:update %s</info>', $recipe->getName()),
             ]);
         }
     }
@@ -292,7 +292,7 @@
                 $treeBar = '└';
             }
 
-            $info = sprintf(
+            $info = \sprintf(
                 '%s──%s',
                 $treeBar,
                 $dir
@@ -319,7 +319,7 @@
                 $treeBar = $previousTreeBar.'  └';
             }
 
-            $info = sprintf(
+            $info = \sprintf(
                 '%s──%s',
                 $treeBar,
                 $dir
diff -ru src/Configurator/DockerComposeConfigurator.php src/Configurator/DockerComposeConfigurator.php
--- src/Configurator/DockerComposeConfigurator.php	2025-03-03 07:50:23.336991116 +0000
+++ src/Configurator/DockerComposeConfigurator.php	2025-03-03 07:50:27.500998547 +0000
@@ -31,7 +31,7 @@
 {
     private $filesystem;
 
-    public static $configureDockerRecipes = null;
+    public static $configureDockerRecipes;
 
     public function __construct(Composer $composer, IOInterface $io, Options $options)
     {
@@ -61,18 +61,18 @@
 
             $name = $recipe->getName();
             // Remove recipe and add break line
-            $contents = preg_replace(sprintf('{%s+###> %s ###.*?###< %s ###%s+}s', "\n", $name, $name, "\n"), \PHP_EOL.\PHP_EOL, file_get_contents($dockerComposeFile), -1, $count);
+            $contents = preg_replace(\sprintf('{%s+###> %s ###.*?###< %s ###%s+}s', "\n", $name, $name, "\n"), \PHP_EOL.\PHP_EOL, file_get_contents($dockerComposeFile), -1, $count);
             if (!$count) {
                 return;
             }
 
             foreach ($extra as $key => $value) {
-                if (0 === preg_match(sprintf('{^%s:[ \t\r\n]*([ \t]+\w|#)}m', $key), $contents, $matches)) {
-                    $contents = preg_replace(sprintf('{\n?^%s:[ \t\r\n]*}sm', $key), '', $contents, -1, $count);
+                if (0 === preg_match(\sprintf('{^%s:[ \t\r\n]*([ \t]+\w|#)}m', $key), $contents, $matches)) {
+                    $contents = preg_replace(\sprintf('{\n?^%s:[ \t\r\n]*}sm', $key), '', $contents, -1, $count);
                 }
             }
 
-            $this->write(sprintf('Removing Docker Compose entries from "%s"', $dockerComposeFile));
+            $this->write(\sprintf('Removing Docker Compose entries from "%s"', $dockerComposeFile));
             file_put_contents($dockerComposeFile, ltrim($contents, "\n"));
         }
 
@@ -181,7 +181,7 @@
                 }
 
                 if (!$this->filesystem->isAbsolutePath($f)) {
-                    $f = realpath(sprintf('%s/%s', $rootDir, $f));
+                    $f = realpath(\sprintf('%s/%s', $rootDir, $f));
                 }
 
                 if ($this->filesystem->exists($f)) {
@@ -194,12 +194,12 @@
         $dir = $rootDir;
         do {
             if (
-                $this->filesystem->exists($dockerComposeFile = sprintf('%s/%s', $dir, $file)) ||
+                $this->filesystem->exists($dockerComposeFile = \sprintf('%s/%s', $dir, $file))
                 // Test with the ".yml" extension if the file doesn't end up with ".yaml"
-                $this->filesystem->exists($dockerComposeFile = substr($dockerComposeFile, 0, -3).'ml') ||
+                || $this->filesystem->exists($dockerComposeFile = substr($dockerComposeFile, 0, -3).'ml')
                 // Test with the legacy "docker-" suffix if "compose.ya?ml" doesn't exist
-                $this->filesystem->exists($dockerComposeFile = sprintf('%s/docker-%s', $dir, $file)) ||
-                $this->filesystem->exists($dockerComposeFile = substr($dockerComposeFile, 0, -3).'ml')
+                || $this->filesystem->exists($dockerComposeFile = \sprintf('%s/docker-%s', $dir, $file))
+                || $this->filesystem->exists($dockerComposeFile = substr($dockerComposeFile, 0, -3).'ml')
             ) {
                 return $dockerComposeFile;
             }
@@ -218,12 +218,12 @@
             $line .= str_repeat(' ', $indent * $level);
             if (!\is_array($value)) {
                 if (\is_string($key)) {
-                    $line .= sprintf('%s:', $key);
+                    $line .= \sprintf('%s:', $key);
                 }
-                $line .= sprintf("%s\n", $value);
+                $line .= \sprintf("%s\n", $value);
                 continue;
             }
-            $line .= sprintf("%s:\n", $key).$this->parse($level + 1, $indent, $value);
+            $line .= \sprintf("%s:\n", $key).$this->parse($level + 1, $indent, $value);
         }
 
         return $line;
@@ -237,14 +237,14 @@
             if (null === $dockerComposeFile) {
                 $dockerComposeFile = $rootDir.'/'.$file;
                 file_put_contents($dockerComposeFile, '');
-                $this->write(sprintf('  Created <fg=green>"%s"</>', $file));
+                $this->write(\sprintf('  Created <fg=green>"%s"</>', $file));
             }
 
             if (!$update && $this->isFileMarked($recipe, $dockerComposeFile)) {
                 continue;
             }
 
-            $this->write(sprintf('Adding Docker Compose definitions to "%s"', $dockerComposeFile));
+            $this->write(\sprintf('Adding Docker Compose definitions to "%s"', $dockerComposeFile));
 
             $offset = 2;
             $node = null;
@@ -317,7 +317,7 @@
                     continue;
                 }
 
-                $lines[] = sprintf("\n%s:", $key);
+                $lines[] = \sprintf("\n%s:", $key);
                 $lines[] = $this->markData($recipe, $this->parse(1, $offset, $value));
             }
 
@@ -372,7 +372,7 @@
     private static function askDockerSupport(IOInterface $io, Recipe $recipe): string
     {
         $warning = $io->isInteractive() ? 'WARNING' : 'IGNORING';
-        $io->writeError(sprintf('  - <warning> %s </> %s', $warning, $recipe->getFormattedOrigin()));
+        $io->writeError(\sprintf('  - <warning> %s </> %s', $warning, $recipe->getFormattedOrigin()));
         $question = '    The recipe for this package contains some Docker configuration.
 
     This may create/update <comment>compose.yaml</comment> or update <comment>Dockerfile</comment> (if it exists).
diff -ru src/Downloader.php src/Downloader.php
--- src/Downloader.php	2025-03-03 07:50:23.971992249 +0000
+++ src/Downloader.php	2025-03-03 07:50:28.736000751 +0000
@@ -176,17 +176,17 @@
             if (0 === strpos($version, 'dev-') && isset($package->getExtra()['branch-alias'])) {
                 $branchAliases = $package->getExtra()['branch-alias'];
                 if (
-                    (isset($branchAliases[$version]) && $alias = $branchAliases[$version]) ||
-                    (isset($branchAliases['dev-main']) && $alias = $branchAliases['dev-main']) ||
-                    (isset($branchAliases['dev-trunk']) && $alias = $branchAliases['dev-trunk']) ||
-                    (isset($branchAliases['dev-develop']) && $alias = $branchAliases['dev-develop']) ||
-                    (isset($branchAliases['dev-default']) && $alias = $branchAliases['dev-default']) ||
-                    (isset($branchAliases['dev-latest']) && $alias = $branchAliases['dev-latest']) ||
-                    (isset($branchAliases['dev-next']) && $alias = $branchAliases['dev-next']) ||
-                    (isset($branchAliases['dev-current']) && $alias = $branchAliases['dev-current']) ||
-                    (isset($branchAliases['dev-support']) && $alias = $branchAliases['dev-support']) ||
-                    (isset($branchAliases['dev-tip']) && $alias = $branchAliases['dev-tip']) ||
-                    (isset($branchAliases['dev-master']) && $alias = $branchAliases['dev-master'])
+                    (isset($branchAliases[$version]) && $alias = $branchAliases[$version])
+                    || (isset($branchAliases['dev-main']) && $alias = $branchAliases['dev-main'])
+                    || (isset($branchAliases['dev-trunk']) && $alias = $branchAliases['dev-trunk'])
+                    || (isset($branchAliases['dev-develop']) && $alias = $branchAliases['dev-develop'])
+                    || (isset($branchAliases['dev-default']) && $alias = $branchAliases['dev-default'])
+                    || (isset($branchAliases['dev-latest']) && $alias = $branchAliases['dev-latest'])
+                    || (isset($branchAliases['dev-next']) && $alias = $branchAliases['dev-next'])
+                    || (isset($branchAliases['dev-current']) && $alias = $branchAliases['dev-current'])
+                    || (isset($branchAliases['dev-support']) && $alias = $branchAliases['dev-support'])
+                    || (isset($branchAliases['dev-tip']) && $alias = $branchAliases['dev-tip'])
+                    || (isset($branchAliases['dev-master']) && $alias = $branchAliases['dev-master'])
                 ) {
                     $version = $alias;
                 }
@@ -244,7 +244,7 @@
 
             // FIXME: Multi name with getNames()
             $name = str_replace('/', ',', $package->getName());
-            $path = sprintf('%s,%s%s', $name, $o, $version);
+            $path = \sprintf('%s,%s%s', $name, $o, $version);
             if ($date = $package->getReleaseDate()) {
                 $path .= ','.$date->format('U');
             }
diff -ru src/Flex.php src/Flex.php
--- src/Flex.php	2025-03-03 07:50:24.264992772 +0000
+++ src/Flex.php	2025-03-03 07:50:32.158006857 +0000
@@ -374,7 +374,7 @@
 
             $this->io->writeError('');
             $this->io->writeError('What about running <comment>composer global require symfony/thanks && composer thanks</> now?');
-            $this->io->writeError(sprintf('This will spread some %s by sending a %s to the GitHub repositories of your fellow package maintainers.', $love, $star));
+            $this->io->writeError(\sprintf('This will spread some %s by sending a %s to the GitHub repositories of your fellow package maintainers.', $love, $star));
         }
 
         $this->io->writeError('');
@@ -392,7 +392,7 @@
             return;
         }
 
-        $this->io->writeError(sprintf('<info>Symfony operations: %d recipe%s (%s)</>', \count($recipes), \count($recipes) > 1 ? 's' : '', $this->downloader->getSessionId()));
+        $this->io->writeError(\sprintf('<info>Symfony operations: %d recipe%s (%s)</>', \count($recipes), \count($recipes) > 1 ? 's' : '', $this->downloader->getSessionId()));
         $installContribs = $this->composer->getPackage()->getExtra()['symfony']['allow-contrib'] ?? false;
         $manifest = null;
         $originalComposerJsonHash = $this->getComposerJsonHash();
@@ -400,8 +400,8 @@
         foreach ($recipes as $recipe) {
             if ('install' === $recipe->getJob() && !$installContribs && $recipe->isContrib()) {
                 $warning = $this->io->isInteractive() ? 'WARNING' : 'IGNORING';
-                $this->io->writeError(sprintf('  - <warning> %s </> %s', $warning, $this->formatOrigin($recipe)));
-                $question = sprintf('    The recipe for this package comes from the "contrib" repository, which is open to community contributions.
+                $this->io->writeError(\sprintf('  - <warning> %s </> %s', $warning, $this->formatOrigin($recipe)));
+                $question = \sprintf('    The recipe for this package comes from the "contrib" repository, which is open to community contributions.
     Review the recipe at %s
 
     Do you want to execute this recipe?
@@ -444,13 +444,13 @@
             switch ($recipe->getJob()) {
                 case 'install':
                     $postInstallRecipes[] = $recipe;
-                    $this->io->writeError(sprintf('  - Configuring %s', $this->formatOrigin($recipe)));
+                    $this->io->writeError(\sprintf('  - Configuring %s', $this->formatOrigin($recipe)));
                     $this->configurator->install($recipe, $this->lock, [
                         'force' => $event instanceof UpdateEvent && $event->force(),
                     ]);
                     $manifest = $recipe->getManifest();
                     if (isset($manifest['post-install-output'])) {
-                        $this->postInstallOutput[] = sprintf('<bg=yellow;fg=white> %s </> instructions:', $recipe->getName());
+                        $this->postInstallOutput[] = \sprintf('<bg=yellow;fg=white> %s </> instructions:', $recipe->getName());
                         $this->postInstallOutput[] = '';
                         foreach ($manifest['post-install-output'] as $line) {
                             $this->postInstallOutput[] = $this->options->expandTargetDir($line);
@@ -461,7 +461,7 @@
                 case 'update':
                     break;
                 case 'uninstall':
-                    $this->io->writeError(sprintf('  - Unconfiguring %s', $this->formatOrigin($recipe)));
+                    $this->io->writeError(\sprintf('  - Unconfiguring %s', $this->formatOrigin($recipe)));
                     $this->configurator->unconfigure($recipe, $this->lock);
                     break;
             }
@@ -594,7 +594,7 @@
             $job = method_exists($operation, 'getOperationType') ? $operation->getOperationType() : $operation->getJobType();
 
             if (!isset($manifests[$name]) && isset($data['conflicts'][$name])) {
-                $this->io->writeError(sprintf('  - Skipping recipe for %s: all versions of the recipe conflict with your package versions.', $name));
+                $this->io->writeError(\sprintf('  - Skipping recipe for %s: all versions of the recipe conflict with your package versions.', $name));
                 continue;
             }
 
@@ -605,7 +605,7 @@
 
                 if (!isset($newManifests[$name])) {
                     // no older recipe found
-                    $this->io->writeError(sprintf('  - Skipping recipe for %s: all versions of the recipe conflict with your package versions.', $name));
+                    $this->io->writeError(\sprintf('  - Skipping recipe for %s: all versions of the recipe conflict with your package versions.', $name));
 
                     continue 2;
                 }
@@ -654,7 +654,7 @@
 
                 if ($bundles) {
                     $manifest = [
-                        'origin' => sprintf('%s:%s@auto-generated recipe', $name, $package->getPrettyVersion()),
+                        'origin' => \sprintf('%s:%s@auto-generated recipe', $name, $package->getPrettyVersion()),
                         'manifest' => ['bundles' => $bundles],
                     ];
                     $recipes[$name] = new Recipe($package, $name, $job, $manifest);
@@ -727,7 +727,7 @@
             return $origin;
         }
 
-        return sprintf('<info>%s</> (<comment>>=%s</>): From %s', $matches[1], $matches[2], 'auto-generated recipe' === $matches[3] ? '<comment>'.$matches[3].'</>' : $matches[3]);
+        return \sprintf('<info>%s</> (<comment>>=%s</>): From %s', $matches[1], $matches[2], 'auto-generated recipe' === $matches[3] ? '<comment>'.$matches[3].'</>' : $matches[3]);
     }
 
     private function shouldRecordOperation(OperationInterface $operation, bool $isDevMode, ?Composer $composer = null): bool
@@ -797,7 +797,7 @@
 
         $this->io->writeError('<info>Unpacking Symfony packs</>');
         foreach ($result->getUnpacked() as $pkg) {
-            $this->io->writeError(sprintf('  - Unpacked <info>%s</>', $pkg->getName()));
+            $this->io->writeError(\sprintf('  - Unpacked <info>%s</>', $pkg->getName()));
         }
 
         $unpacker->updateLock($result, $this->io);
diff -ru src/GithubApi.php src/GithubApi.php
--- src/GithubApi.php	2025-03-03 07:50:24.484993165 +0000
+++ src/GithubApi.php	2025-03-03 07:50:32.540007539 +0000
@@ -40,8 +40,8 @@
             return null;
         }
 
-        $recipePath = sprintf('%s/%s', $package, $version);
-        $commitsData = $this->requestGitHubApi(sprintf(
+        $recipePath = \sprintf('%s/%s', $package, $version);
+        $commitsData = $this->requestGitHubApi(\sprintf(
             'https://api.github.com/repos/%s/commits?path=%s&sha=%s',
             $repositoryName,
             $recipePath,
@@ -85,7 +85,7 @@
             return null;
         }
 
-        $url = sprintf(
+        $url = \sprintf(
             'https://api.github.com/repos/%s/contents/%s?ref=%s',
             $repositoryName,
             $recipePath,
@@ -111,7 +111,7 @@
             return [];
         }
 
-        $commitsData = $this->requestGitHubApi(sprintf(
+        $commitsData = $this->requestGitHubApi(\sprintf(
             'https://api.github.com/repos/%s/commits?path=%s&sha=%s',
             $repositoryName,
             $path,
@@ -142,7 +142,7 @@
         $bestItem = null;
         foreach ($data['items'] as $item) {
             // make sure the PR referenced isn't from a different repository
-            if (false === strpos($item['html_url'], sprintf('%s/pull', $repositoryName))) {
+            if (false === strpos($item['html_url'], \sprintf('%s/pull', $repositoryName))) {
                 continue;
             }
 
diff -ru src/ScriptExecutor.php src/ScriptExecutor.php
--- src/ScriptExecutor.php	2025-03-03 07:50:24.725993595 +0000
+++ src/ScriptExecutor.php	2025-03-03 07:50:32.980008324 +0000
@@ -53,20 +53,20 @@
             $cmdOutput->write($buffer, false, OutputInterface::OUTPUT_RAW);
         };
 
-        $this->io->writeError(sprintf('Executing script %s', $parsedCmd), $this->io->isVerbose());
+        $this->io->writeError(\sprintf('Executing script %s', $parsedCmd), $this->io->isVerbose());
         $exitCode = $this->executor->execute($expandedCmd, $outputHandler);
 
         $code = 0 === $exitCode ? ' <info>[OK]</>' : ' <error>[KO]</>';
 
         if ($this->io->isVerbose()) {
-            $this->io->writeError(sprintf('Executed script %s %s', $cmd, $code));
+            $this->io->writeError(\sprintf('Executed script %s %s', $cmd, $code));
         } else {
             $this->io->writeError($code);
         }
 
         if (0 !== $exitCode) {
             $this->io->writeError(' <error>[KO]</>');
-            $this->io->writeError(sprintf('<error>Script %s returned with error code %s</>', $cmd, $exitCode));
+            $this->io->writeError(\sprintf('<error>Script %s returned with error code %s</>', $cmd, $exitCode));
             fseek($cmdOutput->getStream(), 0);
             foreach (explode("\n", stream_get_contents($cmdOutput->getStream())) as $line) {
                 $this->io->writeError('!!  '.$line);
@@ -86,7 +86,7 @@
             case 'script':
                 return $cmd;
             default:
-                throw new \InvalidArgumentException(sprintf('Invalid symfony/flex auto-script in composer.json: "%s" is not a valid type of command.', $type));
+                throw new \InvalidArgumentException(\sprintf('Invalid symfony/flex auto-script in composer.json: "%s" is not a valid type of command.', $type));
         }
     }
 
@@ -94,7 +94,7 @@
     {
         $repo = $this->composer->getRepositoryManager()->getLocalRepository();
         if (!$repo->findPackage('symfony/console', new MatchAllConstraint())) {
-            $this->io->writeError(sprintf('<warning>Skipping "%s" (needs symfony/console to run).</>', $cmd));
+            $this->io->writeError(\sprintf('<warning>Skipping "%s" (needs symfony/console to run).</>', $cmd));
 
             return null;
         }
diff -ru src/Unpacker.php src/Unpacker.php
--- src/Unpacker.php	2025-03-03 07:50:24.935993970 +0000
+++ src/Unpacker.php	2025-03-03 07:50:33.738009676 +0000
@@ -53,10 +53,10 @@
 
             // not unpackable or no --unpack flag or empty packs (markers)
             if (
-                null === $pkg ||
-                'symfony-pack' !== $pkg->getType() ||
-                !$op->shouldUnpack() ||
-                0 === \count($pkg->getRequires()) + \count($pkg->getDevRequires())
+                null === $pkg
+                || 'symfony-pack' !== $pkg->getType()
+                || !$op->shouldUnpack()
+                || 0 === \count($pkg->getRequires()) + \count($pkg->getDevRequires())
             ) {
                 $result->addRequired($package['name'].($package['version'] ? ':'.$package['version'] : ''));
 
@@ -75,7 +75,7 @@
 
             foreach ($devRequires as $i => $link) {
                 if (!isset($requires[$link->getTarget()])) {
-                    throw new \RuntimeException(sprintf('Symfony pack "%s" must duplicate all entries from "require-dev" into "require" but entry "%s" was not found.', $package['name'], $link->getTarget()));
+                    throw new \RuntimeException(\sprintf('Symfony pack "%s" must duplicate all entries from "require-dev" into "require" but entry "%s" was not found.', $package['name'], $link->getTarget()));
                 }
                 $devRequires[$i] = $requires[$link->getTarget()];
                 unset($requires[$link->getTarget()]);
@@ -161,7 +161,7 @@
             $constraint = end($link['constraints']);
 
             if (!$jsonManipulator->addLink($link['type'], $link['name'], $constraint->getPrettyString(), $op->shouldSort())) {
-                throw new \RuntimeException(sprintf('Unable to unpack package "%s".', $link['name']));
+                throw new \RuntimeException(\sprintf('Unable to unpack package "%s".', $link['name']));
             }
         }
 
diff -ru tests/FlexTest.php tests/FlexTest.php
--- tests/FlexTest.php	2025-03-03 07:50:25.594995145 +0000
+++ tests/FlexTest.php	2025-03-03 07:50:36.136013955 +0000
@@ -163,7 +163,7 @@
                 }
 
                 $expectedManifest = [
-                    'origin' => sprintf('%s:%s@auto-generated recipe', $package->getName(),
+                    'origin' => \sprintf('%s:%s@auto-generated recipe', $package->getName(),
                         $package->getPrettyVersion()),
                     'manifest' => ['bundles' => []],
                 ];

0
Common Typos

0
JSON Files Syntax

0
File Permissions

0
Merge Commits

0
Exception Messages Formatting

0
Usage of void in test files

0
Use ::class whenever possible

0
Deprecation Messages