From 019780dec2af3a270717c61e0255338973da9988 Mon Sep 17 00:00:00 2001 From: Eduardo Pittol Date: Mon, 1 Jan 2024 21:32:29 -0300 Subject: [PATCH 1/2] Make reference optional for distribution filenames --- src/Controller/RepoController.php | 37 +++++++++++++++++++ src/Service/Dist/Storage.php | 16 +++++--- .../ComposerPackageSynchronizer.php | 2 +- .../SensioLabsPackageScanner.php | 2 +- .../Controller/RepoControllerTest.php | 4 ++ 5 files changed, 54 insertions(+), 7 deletions(-) diff --git a/src/Controller/RepoController.php b/src/Controller/RepoController.php index 1eee1319..214f251a 100644 --- a/src/Controller/RepoController.php +++ b/src/Controller/RepoController.php @@ -63,6 +63,14 @@ public function packages(Request $request, Organization $organization): JsonResp ).'dists/%package%/%version%/%reference%.%type%', 'preferred' => true, ], + [ + 'dist-url' => $this->generateUrl( + 'organization_repo_url', + ['organization' => $organization->alias()], + RouterInterface::ABSOLUTE_URL + ).'dists/%package%/%version%/%type%', + 'preferred' => false, + ], ], ])) ->setPrivate() @@ -102,6 +110,35 @@ public function distribution(Organization $organization, string $package, string }); } + /** + * @Route("/dists/{package}/{version}/{type}", + * name="repo_artifact_package_dist", + * host="{organization}{sep1}repo{sep2}{domain}", + * defaults={"domain":"%domain%","sep1"="%organization_separator%","sep2"="%domain_separator%"}, + * requirements={"package"="%package_name_pattern%","type"="zip|tar","domain"="%domain%","sep1"="%organization_separator%","sep2"="%domain_separator%"}, + * methods={"GET"}) + * @Cache(public=false) + */ + public function artifactDistribution(Organization $organization, string $package, string $version, string $type): StreamedResponse + { + $filename = $this->packageManager + ->distFilename($organization->alias(), $package, $version, '', $type) + ->getOrElseThrow(new NotFoundHttpException('This distribution file can not be found or downloaded from origin url.')); + + return new StreamedResponse(function () use ($filename): void { + $outputStream = \fopen('php://output', 'wb'); + if (false === $outputStream) { + throw new HttpException(500, 'Could not open output stream to send binary file.'); // @codeCoverageIgnore + } + $fileStream = $this->packageManager->getDistFileReference($filename); + \stream_copy_to_stream( + $fileStream + ->getOrElseThrow(new NotFoundHttpException('This distribution file can not be found or downloaded from origin url.')), + $outputStream + ); + }); + } + /** * @Route("/downloads", * name="repo_package_downloads", diff --git a/src/Service/Dist/Storage.php b/src/Service/Dist/Storage.php index 76ab3836..bd3f9dea 100644 --- a/src/Service/Dist/Storage.php +++ b/src/Service/Dist/Storage.php @@ -62,14 +62,20 @@ public function remove(Dist $dist): void public function filename(Dist $dist): string { - return \sprintf( - '%s/dist/%s/%s_%s.%s', + $filename = \sprintf( + '%s/dist/%s/%s', $dist->repo(), $dist->package(), - $dist->version(), - $dist->ref(), - $dist->format() + $dist->version() ); + + if ($dist->ref() !== '') { + $filename .= '_'.$dist->ref(); + } + + $filename .= '.'.$dist->format(); + + return $filename; } public function size(Dist $dist): int diff --git a/src/Service/PackageSynchronizer/ComposerPackageSynchronizer.php b/src/Service/PackageSynchronizer/ComposerPackageSynchronizer.php index eda1d6bd..4947ce26 100644 --- a/src/Service/PackageSynchronizer/ComposerPackageSynchronizer.php +++ b/src/Service/PackageSynchronizer/ComposerPackageSynchronizer.php @@ -117,7 +117,7 @@ public function synchronize(Package $package): void 'packageName' => $p->getPrettyName(), 'prettyVersion' => $p->getPrettyVersion(), 'version' => $p->getVersion(), - 'ref' => $p->getDistReference() ?? $p->getDistSha1Checksum(), + 'ref' => $p->getDistReference() ?? '', 'distType' => $p->getDistType(), 'distUrl' => $p->getDistUrl(), 'authHeaders' => $this->getAuthHeaders($package), diff --git a/src/Service/Security/PackageScanner/SensioLabsPackageScanner.php b/src/Service/Security/PackageScanner/SensioLabsPackageScanner.php index 929f9025..e56a2d4e 100644 --- a/src/Service/Security/PackageScanner/SensioLabsPackageScanner.php +++ b/src/Service/Security/PackageScanner/SensioLabsPackageScanner.php @@ -122,7 +122,7 @@ private function findDistribution(Package $package): string ?? $this->versionParser->normalize($packageData['version']); $packageDist = $packageData['dist']; - $reference = $packageDist['reference'] ?? $packageDist['shasum']; + $reference = $packageDist['reference'] ?? ''; if ($packageVersion === $normalizedVersion && isset($packageDist['url'], $reference)) { $archiveType = $packageDist['type']; diff --git a/tests/Functional/Controller/RepoControllerTest.php b/tests/Functional/Controller/RepoControllerTest.php index 0e361cc3..fc803fb6 100644 --- a/tests/Functional/Controller/RepoControllerTest.php +++ b/tests/Functional/Controller/RepoControllerTest.php @@ -105,6 +105,10 @@ public function testOrganizationPackagesAction(): void { "dist-url": "http://buddy.repo.repman.wip/dists/%package%/%version%/%reference%.%type%", "preferred": true + }, + { + "dist-url": "http://buddy.repo.repman.wip/dists/%package%/%version%/%type%", + "preferred": false } ] } From 1706d8d928b9db3acd102a7d0c45ba59e2355022 Mon Sep 17 00:00:00 2001 From: Eduardo Pittol Date: Tue, 2 Jan 2024 19:08:42 -0300 Subject: [PATCH 2/2] Add tests to distribution without reference --- .../Controller/RepoControllerTest.php | 31 ++++++++++++++ .../dist/buddy-works/artifact/1.0.0.0.zip | Bin 0 -> 307 bytes tests/Unit/Service/Dist/StorageTest.php | 38 ++++++++++++++++++ .../ComposerPackageSynchronizerTest.php | 5 +++ 4 files changed, 74 insertions(+) create mode 100644 tests/Resources/buddy/dist/buddy-works/artifact/1.0.0.0.zip create mode 100644 tests/Unit/Service/Dist/StorageTest.php diff --git a/tests/Functional/Controller/RepoControllerTest.php b/tests/Functional/Controller/RepoControllerTest.php index fc803fb6..5989a57e 100644 --- a/tests/Functional/Controller/RepoControllerTest.php +++ b/tests/Functional/Controller/RepoControllerTest.php @@ -150,6 +150,37 @@ public function testOrganizationPackageDistDownload(): void self::assertTrue($this->client->getResponse()->isNotFound()); } + public function testOrganizationArtifactPackageDistDownload(): void + { + $this->fixtures->prepareRepoFiles(); + $this->fixtures->createToken( + $this->fixtures->createOrganization('buddy', $this->fixtures->createUser()), + 'secret-org-token' + ); + + $this->contentFromStream(function (): void { + $this->client->request('GET', '/dists/buddy-works/artifact/1.0.0.0/zip', [], [], [ + 'HTTP_HOST' => 'buddy.repo.repman.wip', + 'PHP_AUTH_USER' => 'token', + 'PHP_AUTH_PW' => 'secret-org-token', + ]); + }); + + $response = $this->client->getResponse(); + self::assertTrue($response->isOk(), 'Response code was not 200, it was instead '.$response->getStatusCode()); + self::assertInstanceOf(StreamedResponse::class, $response); + + $this->contentFromStream(function (): void { + $this->client->request('GET', '/dists/vendor/artifact/1.0.0.0/zip', [], [], [ + 'HTTP_HOST' => 'buddy.repo.repman.wip', + 'PHP_AUTH_USER' => 'token', + 'PHP_AUTH_PW' => 'secret-org-token', + ]); + }); + + self::assertTrue($this->client->getResponse()->isNotFound()); + } + public function testOrganizationTrackDownloads(): void { $this->fixtures->createPackage('c75b535f-5817-41a2-9424-e05476e7958f', 'buddy'); diff --git a/tests/Resources/buddy/dist/buddy-works/artifact/1.0.0.0.zip b/tests/Resources/buddy/dist/buddy-works/artifact/1.0.0.0.zip new file mode 100644 index 0000000000000000000000000000000000000000..1e86802107fe4533c4c1ef08984e0a831ea42bc2 GIT binary patch literal 307 zcmWIWW@Zs#-~hr?Io<&bP|yUVc^MQKlJj#5@{3c8^slFA-B0PZgVz z^6YtI2}`jUX0DJ__(=Wdmtq N1j1+_eF(&1000BCRyqIx literal 0 HcmV?d00001 diff --git a/tests/Unit/Service/Dist/StorageTest.php b/tests/Unit/Service/Dist/StorageTest.php new file mode 100644 index 00000000..a8e289ed --- /dev/null +++ b/tests/Unit/Service/Dist/StorageTest.php @@ -0,0 +1,38 @@ +storage = new Storage( + new FakeDownloader(), + new Filesystem(new MemoryAdapter()) + ); + } + + public function testFilename(): void + { + $dist = new Dist('repo', 'package', '1.1.0', '123456', 'zip'); + + self::assertEquals('repo/dist/package/1.1.0_123456.zip', $this->storage->filename($dist)); + } + + public function testArtifactFilename(): void + { + $dist = new Dist('repo', 'package', '1.1.0', '', 'zip'); + self::assertEquals('repo/dist/package/1.1.0.zip', $this->storage->filename($dist)); + } +} diff --git a/tests/Unit/Service/PackageSynchronizer/ComposerPackageSynchronizerTest.php b/tests/Unit/Service/PackageSynchronizer/ComposerPackageSynchronizerTest.php index b3b854d7..aad6fdfd 100644 --- a/tests/Unit/Service/PackageSynchronizer/ComposerPackageSynchronizerTest.php +++ b/tests/Unit/Service/PackageSynchronizer/ComposerPackageSynchronizerTest.php @@ -109,6 +109,11 @@ public function testSynchronizePackageFromArtifacts(): void self::assertContains('replaces-buddy-works/replace-^1.0', $linkStrings); self::assertContains('conflicts-buddy-works/conflict-^1.0', $linkStrings); self::assertContains('suggests-buddy-works/suggests-You really should', $linkStrings); + + $referencestrings = array_map(function (Version $version): string { + return $version->reference(); + }, $package->versions()->toArray()); + self::assertEquals(['', '', '', ''], $referencestrings); } public function testWithMostRecentUnstable(): void