Skip to content

Commit 15cbfe4

Browse files
committed
Merge branch 'package-details'
2 parents d8ab365 + b43d3a8 commit 15cbfe4

15 files changed

Lines changed: 463 additions & 114 deletions

File tree

assets/stylesheets/dashboard-theme.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,8 @@
6464
.ea-dark-scheme .bg-body-secondary {
6565
--bs-secondary-bg-rgb: var(--dirigent-body-bg-subtle-rgb);
6666
}
67+
68+
.dirigent-package-sidebar div span {
69+
display: inline-block;
70+
width: 120px;
71+
}

src/Controller/Dashboard/DashboardPackagesInfoController.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,14 @@ public function info(string $packageName): Response
3232
$package = $this->packageRepository->findOneBy(['name' => $packageName]);
3333
$version = $package->getLatestVersion();
3434

35+
if (!$version) {
36+
return $this->redirectToRoute('dashboard_packages_versions', ['packageName' => $packageName]);
37+
}
38+
3539
return $this->versionInfo($packageName, $version->getNormalizedVersion());
3640
}
3741

38-
#[Route('/packages/{packageName}/v/{packageVersion}', name: 'dashboard_packages_version_info', requirements: ['packageName' => '[a-z0-9_.-]+/[a-z0-9_.-]+', 'packageVersion' => '.*'])]
42+
#[Route('/packages/{packageName}/versions/{packageVersion}', name: 'dashboard_packages_version_info', requirements: ['packageName' => '[a-z0-9_.-]+/[a-z0-9_.-]+', 'packageVersion' => '.*'])]
3943
#[IsGrantedAccess]
4044
public function versionInfo(string $packageName, string $packageVersion): Response
4145
{
@@ -63,13 +67,9 @@ public function versionInfo(string $packageName, string $packageVersion): Respon
6367
public function versions(string $packageName): Response
6468
{
6569
$package = $this->packageRepository->findOneBy(['name' => $packageName]);
66-
$versions = $package->getVersions()->toArray();
67-
68-
usort($versions, Package::class . '::sortVersions');
6970

7071
return $this->render('dashboard/packages/package_versions.html.twig', [
7172
'package' => $package,
72-
'versions' => $versions,
7373
]);
7474
}
7575

src/Doctrine/Entity/Package.php

Lines changed: 172 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use CodedMonkey\Dirigent\Doctrine\Repository\PackageRepository;
66
use CodedMonkey\Dirigent\Validator\UniquePackage;
7+
use Composer\Package\Version\VersionParser;
78
use Composer\Pcre\Preg;
89
use Doctrine\Common\Collections\ArrayCollection;
910
use Doctrine\Common\Collections\Collection;
@@ -88,6 +89,8 @@ class Package extends TrackedEntity
8889
*/
8990
private array $cachedVersions;
9091

92+
private array $sortedVersions;
93+
9194
public function __construct()
9295
{
9396
$this->installations = new PackageInstallations($this);
@@ -339,19 +342,55 @@ public function setDumpedAt(?\DateTimeImmutable $dumpedAt): void
339342
$this->dumpedAt = $dumpedAt;
340343
}
341344

345+
public function getBrowsableRepositoryUrl(): ?string
346+
{
347+
if (!$this->repositoryUrl) {
348+
return null;
349+
}
350+
351+
if (!Preg::isMatch('{^https?://}i', $this->repositoryUrl)) {
352+
return null;
353+
}
354+
355+
return $this->repositoryUrl;
356+
}
357+
358+
public function getPrettyBrowsableRepositoryUrl(): ?string
359+
{
360+
if (null === $url = $this->getBrowsableRepositoryUrl()) {
361+
return null;
362+
}
363+
364+
$url = preg_replace('#^https?://#', '', $url);
365+
366+
return $url;
367+
}
368+
369+
/**
370+
* @return Version[]
371+
*/
372+
public function getSortedVersions(): array
373+
{
374+
if (!isset($this->sortedVersions)) {
375+
$this->sortedVersions = $this->versions->toArray();
376+
377+
usort($this->sortedVersions, [static::class, 'sortVersions']);
378+
}
379+
380+
return $this->sortedVersions;
381+
}
382+
342383
/**
343-
* Returns the default branch or latest version of the package.
384+
* Returns the default branch or the latest version of the package.
344385
*/
345386
public function getDefaultVersion(): ?Version
346387
{
347-
$versions = $this->versions->toArray();
388+
$versions = $this->getSortedVersions();
348389

349390
if (!count($versions)) {
350391
return null;
351392
}
352393

353-
usort($versions, [static::class, 'sortVersions']);
354-
355394
$latestVersion = reset($versions);
356395
foreach ($versions as $version) {
357396
if ($version->isDefaultBranch()) {
@@ -363,18 +402,17 @@ public function getDefaultVersion(): ?Version
363402
}
364403

365404
/**
366-
* Returns the latest (numbered) version of the package, or the default version if no versions were found.
405+
* The latest (numbered) version of the package, or the default version if no versions were found.
367406
*/
368407
public function getLatestVersion(): ?Version
369408
{
370-
$versions = $this->versions->toArray();
409+
$versions = $this->getSortedVersions();
371410

372411
if (!count($versions)) {
373412
return null;
374413
}
375414

376-
usort($versions, [static::class, 'sortVersions']);
377-
415+
// Return the first non-development version
378416
foreach ($versions as $version) {
379417
if (!$version->isDevelopment()) {
380418
return $version;
@@ -384,6 +422,132 @@ public function getLatestVersion(): ?Version
384422
return $this->getDefaultVersion();
385423
}
386424

425+
/**
426+
* The latest version of each major version.
427+
*
428+
* @return Version[]
429+
*/
430+
public function getActiveVersions(): array
431+
{
432+
$activeVersions = [];
433+
$activePrereleaseVersions = [];
434+
435+
foreach ($this->getSortedVersions() as $version) {
436+
if ('stable' !== VersionParser::parseStability($version->getNormalizedVersion())) {
437+
continue;
438+
}
439+
440+
[$majorVersion, $minorVersion] = explode('.', $version->getNormalizedVersion());
441+
442+
if ('0' === $majorVersion) {
443+
$prereleaseVersion = "$majorVersion.$minorVersion";
444+
445+
$activePrereleaseVersions[$prereleaseVersion] ??= $version;
446+
if (version_compare($version->getNormalizedVersion(), $activePrereleaseVersions[$prereleaseVersion]->getNormalizedVersion(), '>')) {
447+
$activePrereleaseVersions[$prereleaseVersion] = $version;
448+
}
449+
450+
continue;
451+
}
452+
453+
$activeVersions[$majorVersion] ??= $version;
454+
if (version_compare($version->getNormalizedVersion(), $activeVersions[$majorVersion]->getNormalizedVersion(), '>')) {
455+
$activeVersions[$majorVersion] = $version;
456+
}
457+
}
458+
459+
$activeDevelopmentVersions = [];
460+
$activePrereleaseDevelopmentVersions = [];
461+
462+
// Find newer unstable releases of active versions
463+
foreach ($this->getSortedVersions() as $version) {
464+
if (in_array(VersionParser::parseStability($version->getNormalizedVersion()), ['stable', 'dev'], true)) {
465+
continue;
466+
}
467+
468+
[$majorVersion, $minorVersion] = explode('.', $version->getNormalizedVersion());
469+
470+
$developmentVersion = "$majorVersion.$minorVersion";
471+
472+
if ('0' === $majorVersion) {
473+
if (isset($activePrereleaseVersions[$developmentVersion]) && !version_compare($version->getNormalizedVersion(), $activePrereleaseVersions[$developmentVersion]->getNormalizedVersion(), '>')) {
474+
continue;
475+
}
476+
477+
$activePrereleaseDevelopmentVersions[$developmentVersion] ??= $version;
478+
if (version_compare($version->getNormalizedVersion(), $activePrereleaseDevelopmentVersions[$developmentVersion]->getNormalizedVersion(), '>')) {
479+
$activePrereleaseDevelopmentVersions[$developmentVersion] = $version;
480+
}
481+
482+
continue;
483+
}
484+
485+
if (isset($activeVersions[$majorVersion]) && !version_compare($version->getNormalizedVersion(), $activeVersions[$majorVersion]->getNormalizedVersion(), '>')) {
486+
continue;
487+
}
488+
489+
$activeDevelopmentVersions[$developmentVersion] ??= $version;
490+
if (version_compare($version->getNormalizedVersion(), $activeDevelopmentVersions[$developmentVersion]->getNormalizedVersion(), '>')) {
491+
$activeDevelopmentVersions[$version->getNormalizedVersion()] = $version;
492+
}
493+
}
494+
495+
$activeVersions = [...$activeVersions, ...$activeDevelopmentVersions];
496+
497+
if (count($activeVersions)) {
498+
usort($activeVersions, [static::class, 'sortVersions']);
499+
500+
return $activeVersions;
501+
}
502+
503+
// Only show pre-release versions (0.x.x) if no versions after 1.0.0 was found
504+
$activePrereleaseVersions = [...$activePrereleaseVersions, ...$activePrereleaseDevelopmentVersions];
505+
506+
usort($activePrereleaseVersions, [static::class, 'sortVersions']);
507+
508+
return $activePrereleaseVersions;
509+
}
510+
511+
/**
512+
* All non-development versions that are not part of the active versions.
513+
*
514+
* @return Version[]
515+
*/
516+
public function getHistoricalVersions(): array
517+
{
518+
$historicalVersions = array_filter($this->getSortedVersions(), static fn (Version $version) => !$version->isDevelopment());
519+
520+
return array_diff($historicalVersions, $this->getActiveVersions());
521+
}
522+
523+
/**
524+
* All development versions associated with a version number (2.0.x-dev, 0.1.x-dev).
525+
*
526+
* @return Version[]
527+
*/
528+
public function getDevVersions(): array
529+
{
530+
return array_filter($this->getSortedVersions(), static function (Version $version) {
531+
if (str_ends_with($version->getNormalizedVersion(), '.9999999-dev')) {
532+
return true;
533+
}
534+
535+
static $parser = new VersionParser();
536+
537+
return $version->hasVersionAlias() && str_ends_with($parser->normalize($version->getVersionAlias()), '.9999999-dev');
538+
});
539+
}
540+
541+
/**
542+
* All development versions associated with a branch (dev-main, dev-master, dev-develop).
543+
*
544+
* @return Version[]
545+
*/
546+
public function getDevBranchVersions(): array
547+
{
548+
return array_filter($this->getSortedVersions(), static fn (Version $version) => str_starts_with($version->getNormalizedVersion(), 'dev-'));
549+
}
550+
387551
public static function sortVersions(Version $a, Version $b): int
388552
{
389553
$aVersion = $a->getNormalizedVersion();

src/Doctrine/Entity/Version.php

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,21 @@ public function setReleasedAt(?\DateTimeImmutable $releasedAt): void
503503
$this->releasedAt = $releasedAt;
504504
}
505505

506+
public function getSourceReference(): ?string
507+
{
508+
return $this->source['reference'] ?? null;
509+
}
510+
511+
public function getSourceType(): ?string
512+
{
513+
return $this->source['type'] ?? null;
514+
}
515+
516+
public function getSourceUrl(): ?string
517+
{
518+
return $this->source['url'] ?? null;
519+
}
520+
506521
public function getDistReference(): ?string
507522
{
508523
return $this->dist['reference'] ?? null;
@@ -518,6 +533,11 @@ public function getDistUrl(): ?string
518533
return $this->dist['url'] ?? null;
519534
}
520535

536+
public function getReference(): ?string
537+
{
538+
return $this->source['reference'] ?? $this->dist['reference'] ?? null;
539+
}
540+
521541
public function hasVersionAlias(): bool
522542
{
523543
return $this->isDevelopment() && $this->getVersionAlias();
@@ -537,6 +557,11 @@ public function getVersionAlias(): string
537557
return '';
538558
}
539559

560+
public function getVersionTitle(): string
561+
{
562+
return $this->version . ($this->hasVersionAlias() ? ' / ' . $this->getVersionAlias() : '');
563+
}
564+
540565
/**
541566
* Get funding, sorted to help the V2 metadata compression algo.
542567
*
@@ -559,28 +584,6 @@ public function getFundingSorted(): ?array
559584
return $funding;
560585
}
561586

562-
public function getPublicUrl(): ?string
563-
{
564-
$url = $this->getHomepage() ?? $this->getSource()['url'] ?? null;
565-
566-
if (!$url || (!str_starts_with($url, 'http://') && !str_starts_with($url, 'https://'))) {
567-
return null;
568-
}
569-
570-
return $url;
571-
}
572-
573-
public function getPrettyPublicUrl(): ?string
574-
{
575-
if (null === $url = $this->getPublicUrl()) {
576-
return null;
577-
}
578-
579-
$url = preg_replace('#^https?://#', '', $url);
580-
581-
return $url;
582-
}
583-
584587
public function getMajorVersion(): int
585588
{
586589
$split = explode('.', $this->version);

src/Package/PackageMetadataResolver.php

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,8 @@ private function resolveVcsRepository(Package $package): void
156156
foreach ($composerPackages as $composerPackage) {
157157
if ($composerPackage->isDefaultBranch()) {
158158
$package->setRepositoryUrl($composerPackage->getSourceUrl());
159+
160+
return;
159161
}
160162
}
161163
}
@@ -166,8 +168,8 @@ private function resolveVcsRepository(Package $package): void
166168
private function updatePackage(Package $package, array $composerPackages, ?VcsDriverInterface $driver = null): void
167169
{
168170
$existingVersions = $this->versionRepository->getVersionMetadataForUpdate($package);
169-
/** @var ?string $primaryVersionName Version name to use as the package link source */
170-
$primaryVersionName = null;
171+
/** @var ?CompletePackageInterface $primaryVersion Version to use as the package info source */
172+
$primaryVersion = null;
171173

172174
foreach ($composerPackages as $composerPackage) {
173175
if ($composerPackage instanceof AliasPackage) {
@@ -185,19 +187,22 @@ private function updatePackage(Package $package, array $composerPackages, ?VcsDr
185187
$versionName = $version->getNormalizedVersion();
186188

187189
// Use the first version which should be the highest stable version by default
188-
if (null === $primaryVersionName) {
189-
$primaryVersionName = $versionName;
190-
}
190+
$primaryVersion ??= $version;
191191
// If default branch is present however we prefer that as the canonical package link source
192192
if ($version->isDefaultBranch()) {
193-
$primaryVersionName = $versionName;
193+
$primaryVersion = $version;
194194
}
195195

196196
unset($existingVersions[$versionName]);
197197
}
198198

199-
if ($primaryVersionName) {
200-
$message = Envelope::wrap(new UpdatePackageLinks($package->getId(), $primaryVersionName))
199+
if ($primaryVersion) {
200+
// Only update the repository URL if the package is mirrored
201+
if ($package->getMirrorRegistry()) {
202+
$package->setRepositoryUrl($primaryVersion->getSourceUrl());
203+
}
204+
205+
$message = Envelope::wrap(new UpdatePackageLinks($package->getId(), $primaryVersion->getNormalizedVersion()))
201206
->with(new DispatchAfterCurrentBusStamp())
202207
->with(new TransportNamesStamp('async'));
203208
$this->messenger->dispatch($message);

0 commit comments

Comments
 (0)