diff --git a/ux.symfony.com/src/Controller/ChangelogController.php b/ux.symfony.com/src/Controller/ChangelogController.php index 6844575bfb7..34fabafe599 100644 --- a/ux.symfony.com/src/Controller/ChangelogController.php +++ b/ux.symfony.com/src/Controller/ChangelogController.php @@ -12,6 +12,10 @@ namespace App\Controller; use App\Service\Changelog\ChangelogProvider; +use App\Service\Packagist\PackagistDataProvider; +use App\Service\UxPackageRepository; +use App\Twig\Components\ChangelogItem; +use DateTimeImmutable; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Attribute\Route; @@ -20,7 +24,8 @@ class ChangelogController extends AbstractController { public function __construct( private readonly ChangelogProvider $changeLogProvider, - ) { + ) + { } #[Route('/changelog', name: 'app_changelog')] @@ -32,4 +37,38 @@ public function __invoke(): Response 'changelog' => $changelog, ]); } + + #[Route('/{package}/changelog', name: 'app_changelog_package')] + public function package(string $package, UxPackageRepository $packageRepository, PackagistDataProvider $packagistData): Response + { + $uxPackage = $packageRepository->find($package); + + $packageLog = $this->changeLogProvider->getPackageChangelog('ux-'.$uxPackage->getName()); + $packageData = $packagistData->getPackageData($uxPackage->getComposerName()); + + $firstLine = array_shift($packageLog); + + $changelog = []; + foreach ($packageLog as $a) { + $lines = explode("\n", $a); + $version = array_shift($lines); + + $versionData = $packageData['versions']['v'.$version] ?? []; + if ([] === $versionData) { + continue; + } + + $changelog[] = [ + 'body' => implode("\n", $lines), + 'version' => $version, + 'name' => 'v'.$version, + 'date' => $versionData['time'] ?? null, + ]; + } + + return $this->render('ux_packages/package_changelog.html.twig', [ + 'package' => $uxPackage, + 'changelog' => $changelog, + ]); + } } diff --git a/ux.symfony.com/src/Controller/UxPackageController.php b/ux.symfony.com/src/Controller/UxPackageController.php new file mode 100644 index 00000000000..caabb310111 --- /dev/null +++ b/ux.symfony.com/src/Controller/UxPackageController.php @@ -0,0 +1,87 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace App\Controller; + +use App\Service\Changelog\ChangelogProvider; +use App\Service\Packagist\PackagistDataProvider; +use App\Service\UxPackageRepository; +use App\Twig\Components\ChangelogItem; +use DateTimeImmutable; +use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\Routing\Attribute\Route; + +#[Route('/{package}', name: 'app_package')] +class UxPackageController extends AbstractController +{ + public function __construct( + private readonly UxPackageRepository $packageRepository, + private readonly ChangelogProvider $changeLogProvider, + private readonly PackagistDataProvider $packagistData, + ) + { + } + + #[Route('/changelog', name: 'app_package_changelog')] + public function changelog(string $package): Response + { + $uxPackage = $this->packageRepository->find($package) ?? throw $this->createNotFoundException(sprintf('Package "%s" not found', $package)); + + $packageLog = $this->changeLogProvider->getPackageChangelog('ux-'.$uxPackage->getName()); + $packageData = $this->packagistData->getPackageData($uxPackage->getComposerName()); + + $firstLine = array_shift($packageLog); + + $changelog = []; + foreach ($packageLog as $a) { + + $lines = explode("\n", $a); + $version = array_shift($lines); + + $versionData = $packageData['versions']['v'.$version] ?? []; + if ([] === $versionData) { + continue; + } + + $changelog[] = [ + 'body' => implode("\n", $lines), + 'version' => $version, + 'name' => 'v'.$version, + 'date' => $versionData['time'] ?? null, + ]; + } + + return $this->render('ux_packages/package_changelog.html.twig', [ + 'package' => $uxPackage, + 'changelog' => $changelog, + ]); + } + + #[Route('/requirements', name: 'app_package_requirements')] + public function requirements(string $package): Response + { + $uxPackage = $this->packageRepository->find($package) ?? throw $this->createNotFoundException(sprintf('Package "%s" not found', $package)); + + $packageData = $this->packagistData->getPackageData($uxPackage->getComposerName()); + + $packageVersions = $packageData['versions'] ?? []; + $currentVersion = array_shift($packageVersions); + + return $this->render('ux_packages/package_requirements.html.twig', [ + 'package' => $uxPackage, + 'requirements' => [ + 'requires' => $currentVersion['require'] ?? [], + 'devRequires' => $currentVersion['require-dev'] ?? [], + ], + ]); + } +} diff --git a/ux.symfony.com/src/Service/Changelog/ChangelogProvider.php b/ux.symfony.com/src/Service/Changelog/ChangelogProvider.php index e609cde335c..049953968e4 100644 --- a/ux.symfony.com/src/Service/Changelog/ChangelogProvider.php +++ b/ux.symfony.com/src/Service/Changelog/ChangelogProvider.php @@ -30,20 +30,48 @@ public function getChangelog(int $page = 1): array { $changelog = []; - foreach ($this->getReleases($page) as $release) { + foreach ($this->getReleases('ux', $page) as $release) { $changelog[] = $release; } return $changelog; } - private function getReleases(int $page = 1): array + public function getPackageChangelog(string $repo, int $page = 1): array { - return $this->cache->get('releases-symfony-ux-'.$page, function (CacheItemInterface $item) use ($page) { + $changelogMd = $this->cache->get('changelog-symfony-'.$repo.'-'.$page, function (CacheItemInterface $item) use ($repo, $page) { $item->expiresAfter(604800); // 1 week - return $this->fetchReleases('symfony', 'ux', $page); + return $this->fetchPackageChangelog('symfony', $repo, $page); }); + + $changelog = []; + $changelogMarkdown = explode("\n## ", $changelogMd); + + return $changelogMarkdown; + } + + private function getReleases(string $repo, int $page = 1): array + { + return $this->cache->get('releases-symfony-'.$repo.'-'.$page, function (CacheItemInterface $item) use ($repo, $page) { + $item->expiresAfter(604800); // 1 week + + return $this->fetchReleases('symfony', $repo, $page); + }); + } + + /** + * @return string + * + * @internal + */ + private function fetchPackageChangelog(string $owner, string $repo): string + { + // https://github.com/symfony/ux-twig-component/blob/2.x/CHANGELOG.md + // https://raw.githubusercontent.com/symfony/ux-twig-component/2.x/CHANGELOG.md + $response = $this->httpClient->request('GET', sprintf('https://raw.githubusercontent.com/%s/%s/2.x/CHANGELOG.md', $owner, $repo)); + + return $response->getContent(); } /** diff --git a/ux.symfony.com/src/Service/Packagist/PackagistDataProvider.php b/ux.symfony.com/src/Service/Packagist/PackagistDataProvider.php new file mode 100644 index 00000000000..351c2371600 --- /dev/null +++ b/ux.symfony.com/src/Service/Packagist/PackagistDataProvider.php @@ -0,0 +1,35 @@ +cache->get('package-data-'.str_replace('/', '--', $packageName), function (ItemInterface $item) use ($packageName) { + $item->expiresAfter(604800); // 1 week + + return $this->fetchPackageData($packageName); + }); + } + + private function fetchPackageData(string $packageName): array + { + $response = $this->httpClient->request('GET', 'https://packagist.org/packages/'.$packageName.'.json'); + + $packageData = $response->toArray(); + + return $packageData['package'] ?? []; + } +} diff --git a/ux.symfony.com/templates/ux_packages/package_changelog.html.twig b/ux.symfony.com/templates/ux_packages/package_changelog.html.twig new file mode 100644 index 00000000000..a6d5678f5c3 --- /dev/null +++ b/ux.symfony.com/templates/ux_packages/package_changelog.html.twig @@ -0,0 +1,58 @@ +{% extends 'base.html.twig' %} + +{% set meta = { + title: package.humanName, + description: package.description, + canonical: url(package.route), +} %} + +{% block header %} + {{ include('_header.html.twig', { + theme: 'white' + }) }} +{% endblock %} + +{% block content %} + +
+ + {% block package_header %} + {{ block('package_header', 'ux_packages/%s.html.twig'|format(package.name|u.snake)) }} + + + {% endblock %} + + {% block package_content %} + +
+
+

Changelog

+

New features, bug fixes, performances and security improvements.

+
+
+ +
+
+ {% for entry in changelog %} + + {% endfor %} +
+
+ + {% endblock %} +
+ +{% endblock %} diff --git a/ux.symfony.com/templates/ux_packages/package_requirements.html.twig b/ux.symfony.com/templates/ux_packages/package_requirements.html.twig new file mode 100644 index 00000000000..5d36e96aff4 --- /dev/null +++ b/ux.symfony.com/templates/ux_packages/package_requirements.html.twig @@ -0,0 +1,55 @@ +{% extends 'base.html.twig' %} + +{% set meta = { + title: package.humanName, + description: package.description, + canonical: url(package.route), +} %} + +{% block header %} + {{ include('_header.html.twig', { + theme: 'white' + }) }} +{% endblock %} + +{% block content %} + +
+ + {% block package_header %} + {{ block('package_header', 'ux_packages/%s.html.twig'|format(package.name|u.snake)) }} + + + {% endblock %} + + {% block package_content %} + +
+
+

{{ package.name }} Requirements

+

New features, bug fixes, performances and security improvements.

+
+
+ +
+ + {{ dump(requirements) }} +
+ + {% endblock %} +
+ +{% endblock %}