Skip to content

Commit

Permalink
Merge pull request #11157 from lekoala/patch-46
Browse files Browse the repository at this point in the history
FIX use composer runtime api
  • Loading branch information
GuySartorelli authored Feb 27, 2024
2 parents c2b606c + 59177dd commit 4f3282b
Show file tree
Hide file tree
Showing 6 changed files with 41 additions and 216 deletions.
2 changes: 2 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
],
"require": {
"php": "^8.1",
"composer-runtime-api": "^2.0",
"composer/installers": "^2.2",
"guzzlehttp/guzzle": "^7.5.0",
"guzzlehttp/psr7": "^2.4.0",
Expand Down Expand Up @@ -60,6 +61,7 @@
"ext-xml": "*"
},
"require-dev": {
"composer/semver": "^3.4",
"phpunit/phpunit": "^9.6",
"silverstripe/versioned": "^2",
"squizlabs/php_codesniffer": "^3.7",
Expand Down
48 changes: 25 additions & 23 deletions src/Core/Manifest/VersionProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
namespace SilverStripe\Core\Manifest;

use InvalidArgumentException;
use SilverStripe\Core\Config\Config;
use Composer\InstalledVersions;
use SilverStripe\Dev\Deprecation;
use Psr\SimpleCache\CacheInterface;
use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\Core\Config\Configurable;
use SilverStripe\Core\Injector\Injectable;
use SilverStripe\Core\Injector\Injector;

/**
* The version provider will look up configured modules and examine the composer.lock file
Expand All @@ -30,7 +32,7 @@ class VersionProvider
use Injectable;

/**
* @var array
* @var array<string,string>
*/
private static $modules = [
'silverstripe/framework' => 'Framework',
Expand All @@ -50,10 +52,10 @@ public function getVersion()
return $version;
}
$modules = $this->getModules();
$lockModules = $this->getModuleVersionFromComposer(array_keys($modules ?? []));
$lockModules = $this->getModuleVersionFromComposer(array_keys($modules));
$moduleVersions = [];
foreach ($modules as $module => $title) {
if (!array_key_exists($module, $lockModules ?? [])) {
if (!array_key_exists($module, $lockModules)) {
continue;
}
$version = $lockModules[$module];
Expand Down Expand Up @@ -145,14 +147,14 @@ private function setCacheValue(string $key, string $value): void
* cwp/cwp-core => ['CWP', '4.4.4']
* ]
*
* @param array $modules
* @return array
* @param array<string,array<int,string>> $modules
* @return array<string,array<int,string>>
*/
private function filterModules(array $modules)
{
$accountModule = [];
foreach ($modules as $module => $value) {
if (!preg_match('#^([a-z0-9\-]+)/([a-z0-9\-]+)$#', $module ?? '', $m)) {
if (!preg_match('#^([a-z0-9\-]+)/([a-z0-9\-]+)$#', $module, $m)) {
continue;
}
$account = $m[1];
Expand All @@ -169,7 +171,7 @@ private function filterModules(array $modules)
/**
* Gets the configured core modules to use for the SilverStripe application version
*
* @return array
* @return array<string,string>
*/
public function getModules()
{
Expand All @@ -180,55 +182,55 @@ public function getModules()
/**
* Tries to obtain version number from composer.lock if it exists
*
* @param array $modules
* @return array
* @param array<string> $modules
* @return array<string|string>
*/
public function getModuleVersionFromComposer($modules = [])
{
$versions = [];
$lockData = $this->getComposerLock();
if ($lockData && !empty($lockData['packages'])) {
foreach ($lockData['packages'] as $package) {
if (in_array($package['name'], $modules ?? []) && isset($package['version'])) {
$versions[$package['name']] = $package['version'];
}
}
foreach ($modules as $module) {
$versions[$module] = InstalledVersions::getPrettyVersion($module);
}
return $versions;
}

/**
* Load composer.lock's contents and return it
*
* @deprecated 5.1 Has been replaced by composer-runtime-api
* @param bool $cache
* @return array
*/
protected function getComposerLock($cache = true)
{
Deprecation::notice("5.1", "Has been replaced by composer-runtime-api", Deprecation::SCOPE_METHOD);
$composerLockPath = $this->getComposerLockPath();
if (!file_exists($composerLockPath ?? '')) {
if (!file_exists($composerLockPath)) {
return [];
}

$lockData = [];
$jsonData = file_get_contents($composerLockPath ?? '');
$jsonData = file_get_contents($composerLockPath);
$jsonData = $jsonData ? $jsonData : '';
$cacheKey = md5($jsonData);

if ($cache) {
$cache = Injector::inst()->get(CacheInterface::class . '.VersionProvider_composerlock');
$cacheKey = md5($jsonData ?? '');
if ($versions = $cache->get($cacheKey)) {
$lockData = json_decode($versions ?? '', true);
$lockData = json_decode($versions, true);
}
}

if (empty($lockData) && $jsonData) {
$lockData = json_decode($jsonData ?? '', true);
$lockData = json_decode($jsonData, true);

if ($cache) {
$cache->set($cacheKey, $jsonData);
}
}

$lockData = $lockData ? $lockData : [];

return $lockData;
}

Expand Down
143 changes: 14 additions & 129 deletions tests/php/Core/Manifest/VersionProviderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@

namespace SilverStripe\Core\Tests\Manifest;

use SebastianBergmann\Version;
use Composer\Semver\VersionParser;
use SilverStripe\Dev\SapphireTest;
use Psr\SimpleCache\CacheInterface;
use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\Core\Manifest\VersionProvider;
use SilverStripe\Dev\SapphireTest;

class VersionProviderTest extends SapphireTest
{

/**
* @var VersionProvider
*/
Expand All @@ -22,17 +23,9 @@ protected function setup(): void
$this->clearCache();
}

public function getMockProvider($composerLockPath = '')
public function getProvider()
{
if ($composerLockPath == '') {
// composer.lock file without silverstripe/recipe-core or silverstripe/recipe-cms
$composerLockPath = __DIR__ . '/fixtures/VersionProviderTest/composer.no-recipe.testlock';
}
/** @var VersionProvider $provider */
$provider = $this->getMockBuilder(VersionProvider::class)
->setMethods(['getComposerLockPath'])
->getMock();
$provider->method('getComposerLockPath')->willReturn($composerLockPath);
$provider = Injector::inst()->get(VersionProvider::class);
return $provider;
}

Expand All @@ -44,7 +37,7 @@ public function testGetModules()
'silverstripe/another' => 'Another',
'cwp/cwp-something' => 'CWP something',
]);
$result = $this->getMockProvider()->getModules();
$result = $this->getProvider()->getModules();
$this->assertArrayHasKey('silverstripe/mypackage', $result);
$this->assertArrayHasKey('silverstripe/somepackage', $result);
$this->assertArrayHasKey('silverstripe/another', $result);
Expand All @@ -56,7 +49,7 @@ public function testGetModulesEmpty()
Config::modify()->set(VersionProvider::class, 'modules', []);
$this->assertEquals(
['silverstripe/framework' => 'Framework'],
$this->getMockProvider()->getModules()
$this->getProvider()->getModules()
);
}

Expand All @@ -65,7 +58,7 @@ public function testGetModulesNone()
Config::modify()->remove(VersionProvider::class, 'modules');
$this->assertEquals(
['silverstripe/framework' => 'Framework'],
$this->getMockProvider()->getModules()
$this->getProvider()->getModules()
);
}

Expand All @@ -76,7 +69,7 @@ public function testGetModuleVersionFromComposer()
'silverstripe/framework' => 'Framework',
]);

$result = $this->getMockProvider()->getModules(['silverstripe/framework']);
$result = $this->getProvider()->getModules(['silverstripe/framework']);
$this->assertArrayHasKey('silverstripe/framework', $result);
$this->assertNotEmpty($result['silverstripe/framework']);
}
Expand All @@ -87,131 +80,23 @@ public function testGetVersion()
'silverstripe/siteconfig' => 'SiteConfig',
'silverstripe/framework' => 'Framework'
]);
$result = $this->getMockProvider()->getVersion();
$result = $this->getProvider()->getVersion();
$this->assertStringNotContainsString('SiteConfig: ', $result);
$this->assertStringContainsString('Framework: ', $result);
$this->assertStringNotContainsString(', ', $result);
}

public function testGetVersionNoRecipe()
{
// composer.lock file without silverstripe/recipe-core or silverstripe/recipe-cms
$provider = $this->getMockProvider(__DIR__ . '/fixtures/VersionProviderTest/composer.no-recipe.testlock');

Config::modify()->set(VersionProvider::class, 'modules', []);
$result = $provider->getVersion();
$this->assertStringContainsString('Framework: 1.2.3', $result);

$this->clearCache();

Config::modify()->set(VersionProvider::class, 'modules', [
'silverstripe/framework' => 'Framework',
'silverstripe/recipe-core' => 'Core Recipe',
'silverstripe/cms' => 'CMS',
'silverstripe/recipe-cms' => 'CMS Recipe',
]);
$result = $provider->getVersion();
$this->assertStringNotContainsString('Framework: 1.2.3', $result);
$this->assertStringContainsString('CMS: 4.5.6', $result);
$this->assertStringNotContainsString('Core Recipe: 7.7.7', $result);
$this->assertStringNotContainsString('CMS Recipe: 8.8.8', $result);
}

public function testGetVersionRecipeCore()
{
// composer.lock file with silverstripe/recipe-core but not silverstripe/recipe-cms
$provider = $this->getMockProvider(__DIR__ . '/fixtures/VersionProviderTest/composer.recipe-core.testlock');
Config::modify()->set(VersionProvider::class, 'modules', [
'silverstripe/framework' => 'Framework',
'silverstripe/recipe-core' => 'Core Recipe',
'silverstripe/cms' => 'CMS',
'silverstripe/recipe-cms' => 'CMS Recipe',
]);
$result = $provider->getVersion();
$this->assertStringNotContainsString('Framework: 1.2.3', $result);
$this->assertStringNotContainsString('Core Recipe: 7.7.7', $result);
$this->assertStringContainsString('CMS: 4.5.6', $result);
$this->assertStringNotContainsString('CMS Recipe: 8.8.8', $result);
}

public function testGetVersionRecipeCmsCore()
{
// composer.lock file with silverstripe/recipe-core and silverstripe/recipe-cms
$path = __DIR__ . '/fixtures/VersionProviderTest/composer.recipe-cms-core-and-cwpcore.testlock';
$provider = $this->getMockProvider($path);

Config::modify()->set(VersionProvider::class, 'modules', [
'silverstripe/framework' => 'Framework',
'silverstripe/recipe-core' => 'Core Recipe',
'silverstripe/cms' => 'CMS',
'silverstripe/recipe-cms' => 'CMS Recipe',
]);
$result = $provider->getVersion();

$this->assertStringNotContainsString('Framework: 1.2.3', $result);
$this->assertStringNotContainsString('CMS: 4.5.6', $result);
$this->assertStringNotContainsString('Core Recipe: 7.7.7', $result);
$this->assertStringContainsString('CMS Recipe: 8.8.8', $result);
$this->assertStringNotContainsString('CWP: 9.9.9', $result);

$this->clearCache();

Config::modify()->set(VersionProvider::class, 'modules', [
'silverstripe/framework' => 'Framework',
'silverstripe/recipe-core' => 'Core Recipe',
'silverstripe/cms' => 'CMS',
'silverstripe/recipe-cms' => 'CMS Recipe',
'cwp/cwp-core' => 'CWP',
]);
$result = $provider->getVersion();
$this->assertStringNotContainsString('Framework: 1.2.3', $result);
$this->assertStringNotContainsString('CMS: 4.5.6', $result);
$this->assertStringNotContainsString('Core Recipe: 7.7.7', $result);
$this->assertStringContainsString('CMS Recipe:', $result);
$this->assertStringContainsString('CWP: 9.9.9', $result);
}

public function testGetModulesFromComposerLock()
{
$mock = $this->getMockBuilder(VersionProvider::class)
->setMethods(['getComposerLock'])
->getMock();

$mock->expects($this->exactly(1))
->method('getComposerLock')
->will($this->returnValue([
'packages' => [
[
'name' => 'silverstripe/somepackage',
'version' => '1.2.3'
],
[
'name' => 'silverstripe/another',
'version' => '2.3.4'
]
]
]));

Config::modify()->set(VersionProvider::class, 'modules', [
'silverstripe/somepackage' => 'Some Package'
]);

$result = $mock->getVersion();
$this->assertStringContainsString('Some Package: 1.2.3', $result);
}

public function testGetModuleVersion()
{
$provider = $this->getMockProvider(__DIR__ . '/fixtures/VersionProviderTest/composer.recipe-core.testlock');
$provider = $this->getProvider();
Config::modify()->set(VersionProvider::class, 'modules', [
'silverstripe/framework' => 'Framework',
'silverstripe/recipe-core' => 'Core Recipe'
]);
$this->assertSame('1.2.3', $provider->getModuleVersion('silverstripe/framework'));
// assert that the temporary config changes in getModuleVersion() had no side-effects
$moduleVersion = $provider->getModuleVersion('silverstripe/framework');
$parser = new VersionParser();
$this->assertIsString($parser->normalize($moduleVersion), "Expected a valid semver but got $moduleVersion");
$result = $provider->getVersion();
$this->assertStringNotContainsString('Framework: 1.2.3', $result);
$this->assertStringContainsString('Core Recipe: 7.7.7', $result);
}

private function clearCache()
Expand Down

This file was deleted.

Loading

0 comments on commit 4f3282b

Please sign in to comment.