From e19ef240f72f0b0c4dd8b4a43628f95d82a53a9d Mon Sep 17 00:00:00 2001 From: Steve Boyd Date: Tue, 11 Aug 2020 13:04:48 +1200 Subject: [PATCH] NEW VersionProvider now supports recipes as well as modules --- src/Core/Manifest/VersionProvider.php | 75 ++++++++-- .../php/Core/Manifest/VersionProviderTest.php | 137 +++++++++++++++--- .../composer.no-recipe.testlock | 16 ++ ...poser.recipe-cms-core-and-cwpcore.testlock | 28 ++++ .../composer.recipe-core.testlock | 20 +++ 5 files changed, 246 insertions(+), 30 deletions(-) create mode 100644 tests/php/Core/Manifest/fixtures/VersionProviderTest/composer.no-recipe.testlock create mode 100644 tests/php/Core/Manifest/fixtures/VersionProviderTest/composer.recipe-cms-core-and-cwpcore.testlock create mode 100644 tests/php/Core/Manifest/fixtures/VersionProviderTest/composer.recipe-core.testlock diff --git a/src/Core/Manifest/VersionProvider.php b/src/Core/Manifest/VersionProvider.php index 937128c90..27e92ac31 100644 --- a/src/Core/Manifest/VersionProvider.php +++ b/src/Core/Manifest/VersionProvider.php @@ -25,6 +25,7 @@ use SilverStripe\Core\Injector\Injector; */ class VersionProvider { + use Configurable; /** @@ -41,32 +42,74 @@ class VersionProvider { $modules = $this->getModules(); $lockModules = $this->getModuleVersionFromComposer(array_keys($modules)); - $output = []; + $moduleVersions = []; foreach ($modules as $module => $title) { - $version = isset($lockModules[$module]) - ? $lockModules[$module] - : _t(__CLASS__ . '.VERSIONUNKNOWN', 'Unknown'); - $output[] = $title . ': ' . $version; + if (!array_key_exists($module, $lockModules)) { + continue; + } + $version = $lockModules[$module]; + $moduleVersions[$module] = [$title, $version]; } - return implode(', ', $output); + $moduleVersions = $this->filterModules($moduleVersions); + $ret = []; + foreach ($moduleVersions as $module => $value) { + list($title, $version) = $value; + $ret[] = "$title: $version"; + } + return implode(', ', $ret); } /** - * Gets the configured core modules to use for the SilverStripe application version. Filtering - * is used to ensure that modules can turn the result off for other modules, e.g. CMS can disable Framework. + * Filter modules to only use the last module from a git repo, for example + * + * [ + * silverstripe/framework => ['Framework', 1.1.1'], + * silverstripe/cms => ['CMS', 2.2.2'], + * silverstripe/recipe-cms => ['CMS Recipe', '3.3.3'], + * cwp/cwp-core => ['CWP', '4.4.4'] + * ] + * => + * [ + * silverstripe/recipe-cms => ['CMS Recipe', '3.3.3'], + * cwp/cwp-core => ['CWP', '4.4.4'] + * ] + * + * @param array $modules + * @return array + */ + private function filterModules(array $modules) + { + $accountModule = []; + foreach ($modules as $module => $value) { + if (!preg_match('#^([a-z0-9\-]+)/([a-z0-9\-]+)$#', $module, $m)) { + continue; + } + $account = $m[1]; + $accountModule[$account] = [$module, $value]; + } + $ret = []; + foreach ($accountModule as $account => $arr) { + list($module, $value) = $arr; + $ret[$module] = $value; + } + return $ret; + } + + /** + * Gets the configured core modules to use for the SilverStripe application version * * @return array */ public function getModules() { $modules = Config::inst()->get(self::class, 'modules'); - return $modules ? array_filter($modules) : []; + return !empty($modules) ? $modules : ['silverstripe/framework' => 'Framework']; } /** * Tries to obtain version number from composer.lock if it exists * - * @param array $modules + * @param array $modules * @return array */ public function getModuleVersionFromComposer($modules = []) @@ -86,12 +129,12 @@ class VersionProvider /** * Load composer.lock's contents and return it * - * @param bool $cache + * @param bool $cache * @return array */ protected function getComposerLock($cache = true) { - $composerLockPath = BASE_PATH . '/composer.lock'; + $composerLockPath = $this->getComposerLockPath(); if (!file_exists($composerLockPath)) { return []; } @@ -117,4 +160,12 @@ class VersionProvider return $lockData; } + + /** + * @return string + */ + protected function getComposerLockPath(): string + { + return BASE_PATH . '/composer.lock'; + } } diff --git a/tests/php/Core/Manifest/VersionProviderTest.php b/tests/php/Core/Manifest/VersionProviderTest.php index d521aca3a..5d230e0dc 100644 --- a/tests/php/Core/Manifest/VersionProviderTest.php +++ b/tests/php/Core/Manifest/VersionProviderTest.php @@ -2,46 +2,74 @@ namespace SilverStripe\Core\Tests\Manifest; +use SebastianBergmann\Version; use SilverStripe\Core\Config\Config; use SilverStripe\Core\Manifest\VersionProvider; use SilverStripe\Dev\SapphireTest; class VersionProviderTest extends SapphireTest { + /** * @var VersionProvider */ protected $provider; - public function setUp() + public function getMockProvider($composerLockPath = '') { - parent::setUp(); - $this->provider = new VersionProvider; + 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); + return $provider; } public function testGetModules() { Config::modify()->set(VersionProvider::class, 'modules', [ + 'silverstripe/mypackage' => 'My Package', 'silverstripe/somepackage' => 'Some Package', - 'silverstripe/hidden' => '', - 'silverstripe/another' => 'Another' + 'silverstripe/another' => 'Another', + 'cwp/cwp-something' => 'CWP something', ]); - - $result = $this->provider->getModules(); + $result = $this->getMockProvider()->getModules(); + $this->assertArrayHasKey('silverstripe/mypackage', $result); $this->assertArrayHasKey('silverstripe/somepackage', $result); - $this->assertSame('Some Package', $result['silverstripe/somepackage']); $this->assertArrayHasKey('silverstripe/another', $result); - $this->assertArrayNotHasKey('silverstripe/hidden', $result); + $this->assertArrayHasKey('cwp/cwp-something', $result); + } + + public function testGetModulesEmpty() + { + Config::modify()->set(VersionProvider::class, 'modules', []); + $this->assertEquals( + ['silverstripe/framework' => 'Framework'], + $this->getMockProvider()->getModules() + ); + } + + public function testGetModulesNone() + { + Config::modify()->remove(VersionProvider::class, 'modules'); + $this->assertEquals( + ['silverstripe/framework' => 'Framework'], + $this->getMockProvider()->getModules() + ); } public function testGetModuleVersionFromComposer() { Config::modify()->set(VersionProvider::class, 'modules', [ + 'silverstripe/siteconfig' => 'SiteConfig', 'silverstripe/framework' => 'Framework', - 'silverstripe/siteconfig' => 'SiteConfig' ]); - $result = $this->provider->getModules(['silverstripe/framework']); + $result = $this->getMockProvider()->getModules(['silverstripe/framework']); $this->assertArrayHasKey('silverstripe/framework', $result); $this->assertNotEmpty($result['silverstripe/framework']); } @@ -49,14 +77,87 @@ class VersionProviderTest extends SapphireTest public function testGetVersion() { Config::modify()->set(VersionProvider::class, 'modules', [ - 'silverstripe/framework' => 'Framework', - 'silverstripe/siteconfig' => 'SiteConfig' + 'silverstripe/siteconfig' => 'SiteConfig', + 'silverstripe/framework' => 'Framework' ]); - - $result = $this->provider->getVersion(); - $this->assertContains('SiteConfig: ', $result); + $result = $this->getMockProvider()->getVersion(); + $this->assertNotContains('SiteConfig: ', $result); $this->assertContains('Framework: ', $result); - $this->assertContains(', ', $result); + $this->assertNotContains(', ', $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->assertContains('Framework: 1.2.3', $result); + + 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->assertNotContains('Framework: 1.2.3', $result); + $this->assertContains('CMS: 4.5.6', $result); + $this->assertNotContains('Core Recipe: 7.7.7', $result); + $this->assertNotContains('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->assertNotContains('Framework: 1.2.3', $result); + $this->assertNotContains('Core Recipe: 7.7.7', $result); + $this->assertContains('CMS: 4.5.6', $result); + $this->assertNotContains('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->assertNotContains('Framework: 1.2.3', $result); + $this->assertNotContains('CMS: 4.5.6', $result); + $this->assertNotContains('Core Recipe: 7.7.7', $result); + $this->assertContains('CMS Recipe: 8.8.8', $result); + $this->assertNotContains('CWP: 9.9.9', $result); + + 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->assertNotContains('Framework: 1.2.3', $result); + $this->assertNotContains('CMS: 4.5.6', $result); + $this->assertNotContains('Core Recipe: 7.7.7', $result); + $this->assertContains('CMS Recipe:', $result); + $this->assertContains('CWP: 9.9.9', $result); } public function testGetModulesFromComposerLock() @@ -65,7 +166,7 @@ class VersionProviderTest extends SapphireTest ->setMethods(['getComposerLock']) ->getMock(); - $mock->expects($this->once()) + $mock->expects($this->exactly(1)) ->method('getComposerLock') ->will($this->returnValue([ 'packages' => [ diff --git a/tests/php/Core/Manifest/fixtures/VersionProviderTest/composer.no-recipe.testlock b/tests/php/Core/Manifest/fixtures/VersionProviderTest/composer.no-recipe.testlock new file mode 100644 index 000000000..aad7303d9 --- /dev/null +++ b/tests/php/Core/Manifest/fixtures/VersionProviderTest/composer.no-recipe.testlock @@ -0,0 +1,16 @@ +{ + "_readme": [ + "This is a fixture file for unit tests" + ], + "content-hash": "abc123", + "packages": [ + { + "name": "silverstripe/framework", + "version": "1.2.3" + }, + { + "name": "silverstripe/cms", + "version": "4.5.6" + } + ] +} diff --git a/tests/php/Core/Manifest/fixtures/VersionProviderTest/composer.recipe-cms-core-and-cwpcore.testlock b/tests/php/Core/Manifest/fixtures/VersionProviderTest/composer.recipe-cms-core-and-cwpcore.testlock new file mode 100644 index 000000000..a3beb11f0 --- /dev/null +++ b/tests/php/Core/Manifest/fixtures/VersionProviderTest/composer.recipe-cms-core-and-cwpcore.testlock @@ -0,0 +1,28 @@ +{ + "_readme": [ + "This is a fixture file for unit tests" + ], + "content-hash": "abc888", + "packages": [ + { + "name": "silverstripe/framework", + "version": "1.2.3" + }, + { + "name": "silverstripe/cms", + "version": "4.5.6" + }, + { + "name": "silverstripe/recipe-core", + "version": "7.7.7" + }, + { + "name": "silverstripe/recipe-cms", + "version": "8.8.8" + }, + { + "name": "cwp/cwp-core", + "version": "9.9.9" + } + ] +} diff --git a/tests/php/Core/Manifest/fixtures/VersionProviderTest/composer.recipe-core.testlock b/tests/php/Core/Manifest/fixtures/VersionProviderTest/composer.recipe-core.testlock new file mode 100644 index 000000000..4cf00ce0c --- /dev/null +++ b/tests/php/Core/Manifest/fixtures/VersionProviderTest/composer.recipe-core.testlock @@ -0,0 +1,20 @@ +{ + "_readme": [ + "This is a fixture file for unit tests" + ], + "content-hash": "abc777", + "packages": [ + { + "name": "silverstripe/framework", + "version": "1.2.3" + }, + { + "name": "silverstripe/cms", + "version": "4.5.6" + }, + { + "name": "silverstripe/recipe-core", + "version": "7.7.7" + } + ] +}