diff --git a/CHANGELOG.md b/CHANGELOG.md index 49c92788..9a8daa93 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,9 @@ On next release: - [ ] update src/Kernel.php (REPMAN_VERSION) - [ ] update docker-compose.yml (image tags) +### Fixed +- Prefer VCS tag/branch name over hardcoded `version` in composer.json when syncing packages (tags were silently skipped, webhook/sync looked successful but the release never appeared) + ## [1.3.4] - 2021-06-25 ### Security - Upgrade flysystem to 1.1.4 - fix [CVE-2021-32708](https://github.com/thephpleague/flysystem/security/advisories/GHSA-9f46-5r25-5wfm) diff --git a/src/Service/PackageSynchronizer/ComposerPackageSynchronizer.php b/src/Service/PackageSynchronizer/ComposerPackageSynchronizer.php index eda1d6bd..0a72d20a 100644 --- a/src/Service/PackageSynchronizer/ComposerPackageSynchronizer.php +++ b/src/Service/PackageSynchronizer/ComposerPackageSynchronizer.php @@ -60,8 +60,7 @@ public function synchronize(Package $package): void { try { $io = $this->createIO($package); - /** @var RepositoryInterface $repository */ - $repository = current(RepositoryFactory::defaultRepos($io, $this->createConfig($package, $io))); + $repository = $this->createRepository($package, $io); $json = ['packages' => []]; $packages = $repository->getPackages(); @@ -271,6 +270,24 @@ private function accessToken(Package $package): string return $package->oauthToken()->accessToken($this->tokenRefresher); } + private function createRepository(Package $package, IOInterface $io): RepositoryInterface + { + $config = $this->createConfig($package, $io); + $repoType = $this->repositoryType($package); + + if ($this->isVcsRepositoryType($repoType)) { + return new PreferTagVcsRepository([ + 'type' => $repoType, + 'url' => $package->repositoryUrl(), + ], $io, $config); + } + + /** @var RepositoryInterface $repository */ + $repository = current(RepositoryFactory::defaultRepos($io, $config)); + + return $repository; + } + private function createConfig(Package $package, IOInterface $io): Config { unset(Config::$defaultRepositories['packagist.org']); @@ -278,7 +295,7 @@ private function createConfig(Package $package, IOInterface $io): Config $config->merge([ 'repositories' => [ [ - 'type' => strpos($package->type(), '-oauth') !== false ? 'vcs' : $package->type(), + 'type' => $this->repositoryType($package), 'url' => $package->repositoryUrl(), ], ], @@ -293,4 +310,14 @@ private function createConfig(Package $package, IOInterface $io): Config return $config; } + + private function repositoryType(Package $package): string + { + return strpos($package->type(), '-oauth') !== false ? 'vcs' : $package->type(); + } + + private function isVcsRepositoryType(string $type): bool + { + return \in_array($type, ['vcs', 'git', 'github', 'gitlab', 'bitbucket'], true); + } } diff --git a/src/Service/PackageSynchronizer/IgnoreComposerJsonVersionVcsDriver.php b/src/Service/PackageSynchronizer/IgnoreComposerJsonVersionVcsDriver.php new file mode 100644 index 00000000..d9b1d5d7 --- /dev/null +++ b/src/Service/PackageSynchronizer/IgnoreComposerJsonVersionVcsDriver.php @@ -0,0 +1,135 @@ +driver = $driver; + } + + public function initialize(): void + { + $this->driver->initialize(); + } + + /** + * @param string $identifier + * + * @return mixed[]|null + */ + public function getComposerInformation($identifier) + { + $data = $this->driver->getComposerInformation($identifier); + + if (\is_array($data)) { + unset($data['version']); + } + + return $data; + } + + /** + * @param string $file + * @param string $identifier + * + * @return string|null + */ + public function getFileContent($file, $identifier) + { + return $this->driver->getFileContent($file, $identifier); + } + + /** + * @param string $identifier + * + * @return \DateTime|null + */ + public function getChangeDate($identifier) + { + return $this->driver->getChangeDate($identifier); + } + + public function getRootIdentifier(): string + { + return $this->driver->getRootIdentifier(); + } + + /** + * @return array + */ + public function getBranches(): array + { + return $this->driver->getBranches(); + } + + /** + * @return array + */ + public function getTags(): array + { + return $this->driver->getTags(); + } + + /** + * @param string $identifier + * + * @return mixed[]|null + */ + public function getDist($identifier) + { + return $this->driver->getDist($identifier); + } + + /** + * @param string $identifier + * + * @return mixed[] + */ + public function getSource($identifier) + { + return $this->driver->getSource($identifier); + } + + public function getUrl(): string + { + return $this->driver->getUrl(); + } + + /** + * @param string $identifier + */ + public function hasComposerFile($identifier): bool + { + return $this->driver->hasComposerFile($identifier); + } + + public function cleanup(): void + { + $this->driver->cleanup(); + } + + /** + * @param string $url + * @param bool $deep + */ + public static function supports(IOInterface $io, Config $config, $url, $deep = false): bool + { + return false; + } +} diff --git a/src/Service/PackageSynchronizer/PreferTagVcsRepository.php b/src/Service/PackageSynchronizer/PreferTagVcsRepository.php new file mode 100644 index 00000000..1c581bfe --- /dev/null +++ b/src/Service/PackageSynchronizer/PreferTagVcsRepository.php @@ -0,0 +1,27 @@ +wrappedDriver !== null) { + return $this->wrappedDriver; + } + + $driver = parent::getDriver(); + if ($driver === null) { + return null; + } + + return $this->wrappedDriver = new IgnoreComposerJsonVersionVcsDriver($driver); + } +} diff --git a/tests/Unit/Service/PackageSynchronizer/IgnoreComposerJsonVersionVcsDriverTest.php b/tests/Unit/Service/PackageSynchronizer/IgnoreComposerJsonVersionVcsDriverTest.php new file mode 100644 index 00000000..2fd6e8ed --- /dev/null +++ b/tests/Unit/Service/PackageSynchronizer/IgnoreComposerJsonVersionVcsDriverTest.php @@ -0,0 +1,51 @@ +createMock(VcsDriverInterface::class); + $inner->method('getComposerInformation')->with('abc123')->willReturn([ + 'name' => 'buddy-works/example', + 'version' => '1.0.0', + 'description' => 'Example package', + ]); + + $driver = new IgnoreComposerJsonVersionVcsDriver($inner); + + self::assertSame([ + 'name' => 'buddy-works/example', + 'description' => 'Example package', + ], $driver->getComposerInformation('abc123')); + } + + public function testReturnsNonArrayComposerInformationUnchanged(): void + { + $inner = $this->createMock(VcsDriverInterface::class); + $inner->method('getComposerInformation')->willReturn(null); + + $driver = new IgnoreComposerJsonVersionVcsDriver($inner); + + self::assertNull($driver->getComposerInformation('abc123')); + } + + public function testDelegatesTagsAndUrl(): void + { + $inner = $this->createMock(VcsDriverInterface::class); + $inner->method('getTags')->willReturn(['1.0.0' => 'aaa', '1.0.1' => 'bbb']); + $inner->method('getUrl')->willReturn('https://example.com/repo.git'); + + $driver = new IgnoreComposerJsonVersionVcsDriver($inner); + + self::assertSame(['1.0.0' => 'aaa', '1.0.1' => 'bbb'], $driver->getTags()); + self::assertSame('https://example.com/repo.git', $driver->getUrl()); + } +}