From 7ccf230390da3af45d87c64ada6e2b78f2d1ddfb Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sat, 20 Aug 2022 08:42:20 +0300 Subject: [PATCH] Fix cache invalidation issue when a git tag gets created on an old ref after the cache is populated, fixes #11002 (#11004) --- src/Composer/Downloader/GitDownloader.php | 2 +- src/Composer/Util/Git.php | 24 ++++++++++++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/Composer/Downloader/GitDownloader.php b/src/Composer/Downloader/GitDownloader.php index 3ba921868406..9ba60002ab86 100644 --- a/src/Composer/Downloader/GitDownloader.php +++ b/src/Composer/Downloader/GitDownloader.php @@ -75,7 +75,7 @@ protected function doDownload(PackageInterface $package, string $path, string $u $this->io->writeError(" - Syncing " . $package->getName() . " (" . $package->getFullPrettyVersion() . ") into cache"); $this->io->writeError(sprintf(' Cloning to cache at %s', ProcessExecutor::escape($cachePath)), true, IOInterface::DEBUG); $ref = $package->getSourceReference(); - if ($this->gitUtil->fetchRefOrSyncMirror($url, $cachePath, $ref) && is_dir($cachePath)) { + if ($this->gitUtil->fetchRefOrSyncMirror($url, $cachePath, $ref, $package->getPrettyVersion()) && is_dir($cachePath)) { $this->cachedPackages[$package->getId()][$ref] = true; } } elseif (null === $gitVersion) { diff --git a/src/Composer/Util/Git.php b/src/Composer/Util/Git.php index f43ba052b975..80521ca3bfd8 100644 --- a/src/Composer/Util/Git.php +++ b/src/Composer/Util/Git.php @@ -297,9 +297,31 @@ public function syncMirror(string $url, string $dir): bool return true; } - public function fetchRefOrSyncMirror(string $url, string $dir, string $ref): bool + public function fetchRefOrSyncMirror(string $url, string $dir, string $ref, string $prettyVersion = null): bool { if ($this->checkRefIsInMirror($dir, $ref)) { + if (Preg::isMatch('{^[a-f0-9]{40}$}', $ref) && $prettyVersion !== null) { + $branch = Preg::replace('{(?:^dev-|(?:\.x)?-dev$)}i', '', $prettyVersion); + $branches = null; + $tags = null; + if (0 === $this->process->execute('git branch', $output, $dir)) { + $branches = $output; + } + if (0 === $this->process->execute('git tag', $output, $dir)) { + $tags = $output; + } + + // if the pretty version cannot be found as a branch (nor branch with 'v' in front of the branch as it may have been stripped when generating pretty name), + // nor as a tag, then we sync the mirror as otherwise it will likely fail during install. + // this can occur if a git tag gets created *after* the reference is already put into the cache, as the ref check above will then not sync the new tags + // see https://github.com/composer/composer/discussions/11002 + if (null !== $branches && !Preg::isMatch('{^[\s*]*v?'.preg_quote($branch).'$}m', $branches) + && null !== $tags && !Preg::isMatch('{^[\s*]*'.preg_quote($branch).'$}m', $tags) + ) { + $this->syncMirror($url, $dir); + } + } + return true; }