Skip to content

Commit 90d85bf

Browse files
authored
Merge pull request #150 from cakephp/latest-stable-release-date
add latest stable release date info to package
2 parents d38ec0d + 366a7c8 commit 90d85bf

11 files changed

Lines changed: 77 additions & 3 deletions

File tree

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
use Migrations\BaseMigration;
5+
6+
class AddLatestStableReleaseDateToPackages extends BaseMigration
7+
{
8+
/**
9+
* @return void
10+
*/
11+
public function change(): void
12+
{
13+
$this->table('packages')
14+
->addColumn('latest_stable_release_date', 'date', [
15+
'default' => null,
16+
'null' => true,
17+
])
18+
->update();
19+
}
20+
}
15.8 KB
Binary file not shown.

src/Command/SyncPackagesCommand.php

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@
77
use Cake\Console\Arguments;
88
use Cake\Console\CommandFactoryInterface;
99
use Cake\Console\ConsoleIo;
10+
use Cake\I18n\Date;
1011
use Cake\Log\Log;
1112
use Composer\Semver\Intervals;
1213
use Composer\Semver\VersionParser;
1314
use Packagist\Api\Client;
15+
use Packagist\Api\Result\Package\Version;
1416
use UnexpectedValueException;
1517

1618
/**
@@ -139,7 +141,7 @@ public function execute(Arguments $args, ConsoleIo $io)
139141

140142
/**
141143
* @param string $packageName
142-
* @return array{package: string, description: string, repo_url: string, downloads: int, stars: int, tag_list: array, latest_stable_version: ?string, is_abandoned: bool}
144+
* @return array{package: string, description: string, repo_url: string, downloads: int, stars: int, tag_list: array, latest_stable_version: ?string, latest_stable_release_date: ?\Cake\I18n\Date, is_abandoned: bool}
143145
*/
144146
private function getDataForPackage(string $packageName): array
145147
{
@@ -155,6 +157,7 @@ private function getDataForPackage(string $packageName): array
155157
'stars' => $metaDetails->getGithubStars(),
156158
'tag_list' => [],
157159
'latest_stable_version' => null,
160+
'latest_stable_release_date' => null,
158161
'is_abandoned' => true,
159162
];
160163
}
@@ -183,10 +186,14 @@ private function getDataForPackage(string $packageName): array
183186
}
184187
}
185188

186-
$stableVersions = array_filter($versions, fn($v) => preg_match('/^v?\d+\.\d+(\.\d+)?$/', $v->getVersion()));
189+
$stableVersions = array_filter(
190+
$versions,
191+
fn(Version $version) => preg_match('/^v?\d+\.\d+(\.\d+)?$/', $version->getVersion()),
192+
);
187193
usort($stableVersions, function ($a, $b) {
188194
return version_compare($a->getVersion(), $b->getVersion());
189195
});
196+
/** @var \Packagist\Api\Result\Package\Version|false $latestStable */
190197
$latestStable = end($stableVersions);
191198

192199
return [
@@ -197,10 +204,24 @@ private function getDataForPackage(string $packageName): array
197204
'stars' => $metaDetails->getGithubStars(),
198205
'tag_list' => $meta,
199206
'latest_stable_version' => $latestStable ? $latestStable->getVersion() : null,
207+
'latest_stable_release_date' => $this->extractReleaseDate($latestStable ?: null),
200208
'is_abandoned' => $metaDetails->isAbandoned(),
201209
];
202210
}
203211

212+
/**
213+
* @param \Packagist\Api\Result\Package\Version|null $version
214+
* @return \Cake\I18n\Date|null
215+
*/
216+
private function extractReleaseDate(?Version $version): ?Date
217+
{
218+
if (!$version || $version->getTime() === '') {
219+
return null;
220+
}
221+
222+
return new Date($version->getTime());
223+
}
224+
204225
/**
205226
* @param list<string> $tags
206227
* @return bool

src/Controller/PackagesController.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public function index()
3535
if (empty($queryParams['sort'])) {
3636
$this->request = $this->request->withQueryParams(array_merge(
3737
$queryParams,
38-
['sort' => 'downloads', 'direction' => 'desc'],
38+
['sort' => 'latest_stable_release_date', 'direction' => 'desc'],
3939
));
4040
}
4141

src/Model/Entity/Package.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
* @property int $downloads
1616
* @property int $stars
1717
* @property string|null $latest_stable_version
18+
* @property \Cake\I18n\Date|null $latest_stable_release_date
1819
*
1920
* @property \Tags\Model\Entity\Tag[] $tags
2021
*

src/Model/Table/PackagesTable.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,11 @@ public function validationDefault(Validator $validator): Validator
8686
->requirePresence('latest_stable_version', 'create')
8787
->allowEmptyString('latest_stable_version');
8888

89+
$validator
90+
->date('latest_stable_release_date')
91+
->requirePresence('latest_stable_release_date', 'create')
92+
->allowEmptyDate('latest_stable_release_date');
93+
8994
return $validator;
9095
}
9196
}

templates/Packages/index.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ class="packages index content"
115115
?>
116116
<?= $this->Paginator->sort('downloads', 'Downloads') ?>
117117
<?= $this->Paginator->sort('stars', 'Stars') ?>
118+
<?= $this->Paginator->sort('latest_stable_release_date', 'Latest Release') ?>
118119
</div>
119120
</div>
120121
</div>

templates/element/Packages/package-tile.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,9 @@ class="btn btn-xs <?= $isActive ? $compatibilityGroup['activeClass'] : $compatib
119119
<div class="stat-value text-base">
120120
<?= h($package->latest_stable_version ?: __('Unknown')) ?>
121121
</div>
122+
<div class="stat-desc text-xs">
123+
<?= __('Released {0}', $package->latest_stable_release_date?->i18nFormat('MMM d, yyyy') ?? __('Unknown')) ?>
124+
</div>
122125
</div>
123126
<div class="stat px-4 py-3">
124127
<div class="stat-title text-xs flex items-center gap-2 [&_svg]:size-4">

tests/Fixture/PackagesFixture.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ public function init(): void
2626
'downloads' => 5000,
2727
'stars' => 450,
2828
'latest_stable_version' => '5.0.0',
29+
'latest_stable_release_date' => '2025-01-15',
2930
],
3031
];
3132

@@ -39,6 +40,7 @@ public function init(): void
3940
'downloads' => 1000 - $i,
4041
'stars' => 100 - $i,
4142
'latest_stable_version' => sprintf('1.%d.0', $i - 2),
43+
'latest_stable_release_date' => sprintf('2025-02-%02d', $i),
4244
];
4345
}
4446

tests/TestCase/Command/SyncPackagesCommandTest.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55

66
use App\Command\SyncPackagesCommand;
77
use Cake\Console\TestSuite\ConsoleIntegrationTestTrait;
8+
use Cake\I18n\Date;
89
use Cake\TestSuite\TestCase;
10+
use Packagist\Api\Result\Package\Version;
911
use ReflectionMethod;
1012

1113
/**
@@ -30,6 +32,24 @@ public function testHasExplicitCakePhpDependency(): void
3032
$this->assertFalse($method->invoke($command, ['PHP: 8.2']));
3133
}
3234

35+
/**
36+
* @return void
37+
*/
38+
public function testExtractReleaseDate(): void
39+
{
40+
$command = new SyncPackagesCommand();
41+
$method = new ReflectionMethod($command, 'extractReleaseDate');
42+
$method->setAccessible(true);
43+
44+
$version = new Version();
45+
$version->fromArray([
46+
'time' => '2026-04-05T11:22:33+00:00',
47+
]);
48+
49+
$this->assertEquals(new Date('2026-04-05'), $method->invoke($command, $version));
50+
$this->assertNull($method->invoke($command, null));
51+
}
52+
3353
/**
3454
* Test defaultName method
3555
*

0 commit comments

Comments
 (0)