diff --git a/.editorconfig b/.editorconfig
index 5cadf7b..3fe4879 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -12,3 +12,6 @@ trim_trailing_whitespace = true
[*.yml]
indent_size = 2
+
+[*.neon]
+indent_style = tab
diff --git a/.gitattributes b/.gitattributes
index 43b70c6..371212d 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -8,3 +8,5 @@
phpunit.xml.dist export-ignore
phpcs.xml.dist export-ignore
.github export-ignore
+phpstan.neon export-ignore
+psalm.xml export-ignore
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index f13f908..aa2c840 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -8,78 +8,14 @@ on:
branches:
- '*'
-jobs:
- testsuite-linux:
- runs-on: ubuntu-18.04
- strategy:
- fail-fast: false
- matrix:
- php-version: ['5.6', '7.4', '8.0']
- prefer-lowest: ['']
- include:
- - php-version: '5.6'
- prefer-lowest: 'prefer-lowest'
-
- steps:
- - uses: actions/checkout@v2
-
- - name: Setup PHP
- uses: shivammathur/setup-php@v2
- with:
- coverage: none
- php-version: ${{ matrix.php-version }}
- extensions: mbstring, intl
-
- - name: Get composer cache directory
- id: composer-cache
- run: echo "::set-output name=dir::$(composer config cache-files-dir)"
-
- - name: Get date part for cache key
- id: key-date
- run: echo "::set-output name=date::$(date +'%Y-%m')"
-
- - name: Cache composer dependencies
- uses: actions/cache@v1
- with:
- path: ${{ steps.composer-cache.outputs.dir }}
- key: ${{ runner.os }}-composer-${{ steps.key-date.outputs.date }}-${{ hashFiles('composer.json') }}-${{ matrix.prefer-lowest }}
-
- - name: Composer install
- run: |
- if ${{ matrix.prefer-lowest == 'prefer-lowest' }}; then
- composer update --prefer-lowest --prefer-stable
- else
- composer install
- fi
+permissions:
+ contents: read
- - name: Run PHPUnit
- run: |
- if [[ ${{ matrix.php-version }} == '5.6' ]]; then
- vendor/bin/phpunit tests/php56/
- else
- vendor/bin/phpunit
- fi
+jobs:
+ testsuite:
+ uses: cakephp/.github/.github/workflows/testsuite-without-db.yml@5.x
+ secrets: inherit
cs-stan:
- name: Coding Standard & Static Analysis
- runs-on: ubuntu-18.04
-
- steps:
- - uses: actions/checkout@v2
-
- - name: Setup PHP
- uses: shivammathur/setup-php@v2
- with:
- php-version: '7.4'
- extensions: mbstring, intl
- coverage: none
- tools: psalm:~4.1.0, cs2pr
-
- - name: Composer Install
- run: composer install
-
- - name: Run phpcs
- run: vendor/bin/phpcs --report=checkstyle src/ tests/ | cs2pr
-
- - name: Run psalm
- run: psalm --output-format=github
+ uses: cakephp/.github/.github/workflows/cs-stan.yml@5.x
+ secrets: inherit
diff --git a/composer.json b/composer.json
index 3a14a04..bfa86d3 100644
--- a/composer.json
+++ b/composer.json
@@ -10,13 +10,13 @@
}
],
"require": {
- "php": ">=5.6.0",
+ "php": ">=8.1",
"composer-plugin-api": "^1.0 || ^2.0"
},
"require-dev": {
- "cakephp/cakephp-codesniffer": "^3.3",
+ "cakephp/cakephp-codesniffer": "5.x-dev",
"composer/composer": "^2.0",
- "phpunit/phpunit": "^5.7 || ^6.5 || ^8.5 || ^9.3"
+ "phpunit/phpunit": "^9.5.19"
},
"autoload": {
"psr-4": {
@@ -25,15 +25,17 @@
},
"autoload-dev": {
"psr-4": {
- "Cake\\Test\\TestCase\\Composer\\": "tests/TestCase/",
- "Cake\\Test\\TestCase\\Composer\\Php56\\": "tests/php56/TestCase/"
+ "Cake\\Test\\TestCase\\Composer\\": "tests/TestCase/"
}
},
"extra": {
"class": "Cake\\Composer\\Plugin"
},
"config": {
- "sort-packages": true
+ "sort-packages": true,
+ "allow-plugins": {
+ "dealerdirect/phpcodesniffer-composer-installer": true
+ }
},
"prefer-stable": true
}
diff --git a/phpstan.neon b/phpstan.neon
new file mode 100644
index 0000000..df36ddf
--- /dev/null
+++ b/phpstan.neon
@@ -0,0 +1,4 @@
+parameters:
+ level: 6
+ paths:
+ - src/
diff --git a/psalm.xml b/psalm.xml
index 8dc065a..44c6df8 100644
--- a/psalm.xml
+++ b/psalm.xml
@@ -1,6 +1,6 @@
+
+
+
+
+
diff --git a/src/Installer/PluginInstaller.php b/src/Installer/PluginInstaller.php
deleted file mode 100644
index f1fa998..0000000
--- a/src/Installer/PluginInstaller.php
+++ /dev/null
@@ -1,77 +0,0 @@
- ' . str_pad($text, $width) . '';
- };
-
- $messages = [
- '',
- '',
- $wrap(''),
- $wrap($title),
- $wrap(''),
- ];
-
- $lines = explode("\n", wordwrap($text, 68));
- foreach ($lines as $line) {
- $messages[] = $wrap($line);
- }
-
- $messages = array_merge($messages, [$wrap(''), '', '']);
-
- $io->write($messages);
- }
-
- /**
- * Called whenever composer (re)generates the autoloader
- *
- * Recreates CakePHP's plugin path map, based on composer information
- * and available app-plugins.
- *
- * @param \Composer\Script\Event $event the composer event object
- * @return void
- */
- public static function postAutoloadDump(Event $event)
- {
- $scripts = $event->getComposer()->getPackage()->getScripts();
- if (!isset($scripts['post-autoload-dump'])) {
- return;
- }
-
- $postAutoloadDump = 'Cake\Composer\Installer\PluginInstaller::postAutoloadDump';
- if (
- $scripts['post-autoload-dump'] === $postAutoloadDump
- || (is_array($scripts['post-autoload-dump'])
- && in_array($postAutoloadDump, $scripts['post-autoload-dump'])
- )
- ) {
- static::warnUser(
- 'Action required!',
- 'The CakePHP plugin installer v1.3+ no longer requires the "post-autoload-dump" hook.' .
- ' Please update your app\'s composer.json file and remove usage of ' . $postAutoloadDump,
- $event->getIO()
- );
- }
- }
-}
diff --git a/src/Plugin.php b/src/Plugin.php
index 621ec86..cf65fb9 100644
--- a/src/Plugin.php
+++ b/src/Plugin.php
@@ -1,4 +1,6 @@
getComposer();
$config = $composer->getConfig();
@@ -78,16 +81,16 @@ public function postAutoloadDump(Event $event)
* Add all composer packages of type `cakephp-plugin`, and all plugins located
* in the plugins directory to a plugin-name indexed array of paths.
*
- * @param \Composer\Package\PackageInterface[] $packages Array of \Composer\Package\PackageInterface objects.
- * @param array $pluginDirs The path to the plugins dir.
+ * @param array<\Composer\Package\PackageInterface> $packages Array of \Composer\Package\PackageInterface objects.
+ * @param array $pluginDirs The path to the plugins dir.
* @param string $vendorDir The path to the vendor dir.
- * @return array Plugin name indexed paths to plugins.
+ * @return array Plugin name indexed paths to plugins.
*/
public function findPlugins(
array $packages,
array $pluginDirs = ['plugins'],
- $vendorDir = 'vendor'
- ) {
+ string $vendorDir = 'vendor'
+ ): array {
$plugins = [];
foreach ($packages as $package) {
@@ -103,7 +106,7 @@ public function findPlugins(
foreach ($pluginDirs as $path) {
$path = $this->getFullPath($path, $vendorDir);
if (is_dir($path)) {
- $dir = new \DirectoryIterator($path);
+ $dir = new DirectoryIterator($path);
foreach ($dir as $info) {
if (!$info->isDir() || $info->isDot()) {
continue;
@@ -131,7 +134,7 @@ public function findPlugins(
* @param string $vendorDir The path to the vendor dir.
* @return string
*/
- public function getFullPath($path, $vendorDir)
+ public function getFullPath(string $path, string $vendorDir): string
{
if (preg_match('{^(?:/|[a-z]:|[a-z0-9.]+://)}i', $path)) {
return rtrim($path, '/');
@@ -148,11 +151,11 @@ public function getFullPath($path, $vendorDir)
* Rewrite the config file with a complete list of plugins.
*
* @param string $configFile The path to the config file.
- * @param array $plugins Array of plugins.
+ * @param array $plugins Array of plugins.
* @param string|null $root The root directory. Defaults to a value generated from `$configFile`.
* @return void
*/
- public function writeConfigFile($configFile, array $plugins, $root = null)
+ public function writeConfigFile(string $configFile, array $plugins, ?string $root = null): void
{
$root = $root ?: dirname(dirname($configFile));
@@ -212,7 +215,7 @@ public function writeConfigFile($configFile, array $plugins, $root = null)
* @param string $vendorDir Path to composer-vendor dir.
* @return string Absolute file path.
*/
- public function getConfigFilePath($vendorDir)
+ public function getConfigFilePath(string $vendorDir): string
{
return $vendorDir . DIRECTORY_SEPARATOR . 'cakephp-plugins.php';
}
@@ -224,10 +227,11 @@ public function getConfigFilePath($vendorDir)
* @return string The package's primary namespace.
* @throws \RuntimeException When the package's primary namespace cannot be determined.
*/
- public function getPrimaryNamespace(PackageInterface $package)
+ public function getPrimaryNamespace(PackageInterface $package): string
{
$primaryNs = null;
$autoLoad = $package->getAutoload();
+ /** @var array $pathMap */
foreach ($autoLoad as $type => $pathMap) {
if ($type !== 'psr-4') {
continue;
@@ -265,6 +269,6 @@ public function getPrimaryNamespace(PackageInterface $package)
);
}
- return trim((string)$primaryNs, '\\');
+ return trim($primaryNs, '\\');
}
}
diff --git a/tests/TestCase/Installer/PluginInstallerTest.php b/tests/TestCase/Installer/PluginInstallerTest.php
deleted file mode 100644
index 219214d..0000000
--- a/tests/TestCase/Installer/PluginInstallerTest.php
+++ /dev/null
@@ -1,44 +0,0 @@
-composer = new Composer();
- $this->io = $this->getMockBuilder(IOInterface::class)->getMock();
- }
-
- public function testPostAutoloadDump()
- {
- $rootPackage = new RootPackage('cakephp/app', '1.0', '1.0');
- $rootPackage->setType('project');
- $rootPackage->setScripts([
- 'post-autoload-dump' => 'Cake\Composer\Installer\PluginInstaller::postAutoloadDump',
- ]);
-
- $this->composer->setPackage($rootPackage);
- $this->io->expects($this->once())
- ->method('write');
-
- $event = new Event('post-autoload-dump', $this->composer, $this->io);
-
- PluginInstaller::postAutoloadDump($event);
- }
-}
diff --git a/tests/php56/TestCase/Installer/PluginInstallerTest.php b/tests/php56/TestCase/Installer/PluginInstallerTest.php
deleted file mode 100644
index 92f548c..0000000
--- a/tests/php56/TestCase/Installer/PluginInstallerTest.php
+++ /dev/null
@@ -1,42 +0,0 @@
-composer = new Composer();
- $this->io = $this->getMockBuilder(IOInterface::class)->getMock();
- }
-
- public function testPostAutoloadDump()
- {
- $rootPackage = new RootPackage('cakephp/app', '1.0', '1.0');
- $rootPackage->setType('project');
- $rootPackage->setScripts([
- 'post-autoload-dump' => 'Cake\Composer\Installer\PluginInstaller::postAutoloadDump',
- ]);
-
- $this->composer->setPackage($rootPackage);
- $this->io->expects($this->once())
- ->method('write');
-
- $event = new Event('post-autoload-dump', $this->composer, $this->io);
-
- PluginInstaller::postAutoloadDump($event);
- }
-}
diff --git a/tests/php56/TestCase/PHPUnitAssertionCompatTrait.php b/tests/php56/TestCase/PHPUnitAssertionCompatTrait.php
deleted file mode 100644
index d3c67ac..0000000
--- a/tests/php56/TestCase/PHPUnitAssertionCompatTrait.php
+++ /dev/null
@@ -1,11 +0,0 @@
-assertContains($needle, $haystack, $message);
- }
-}
diff --git a/tests/php56/TestCase/PluginTest.php b/tests/php56/TestCase/PluginTest.php
deleted file mode 100644
index 6c3c2ac..0000000
--- a/tests/php56/TestCase/PluginTest.php
+++ /dev/null
@@ -1,334 +0,0 @@
-package = new Package('cake/plugin', '1.0', '1.0');
- $this->package->setType('cakephp-plugin');
-
- $this->path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'plugin-installer-test';
-
- foreach ($this->testDirs as $dir) {
- if (!is_dir($this->path . '/' . $dir)) {
- mkdir($this->path . '/' . $dir);
- }
- }
-
- $this->composer = new Composer();
- $config = new Config();
- $config->merge([
- 'vendor-dir' => $this->path . '/vendor',
- ]);
-
- $this->composer->setConfig($config);
-
- /** @var \Composer\IO\IOInterface&\PHPUnit\Framework\MockObject\MockObject $io */
- $io = $this->getMockBuilder(IOInterface::class)->getMock();
- $this->io = $io;
-
- $httpDownloader = new HttpDownloader($this->io, $config);
-
- $rm = new RepositoryManager(
- $this->io,
- $config,
- $httpDownloader
- );
- $this->composer->setRepositoryManager($rm);
-
- $this->plugin = new Plugin();
- }
-
- public function tearDown()
- {
- parent::tearDown();
-
- $dirs = array_reverse($this->testDirs);
-
- if (is_file($this->path . '/vendor/cakephp-plugins.php')) {
- unlink($this->path . '/vendor/cakephp-plugins.php');
- }
-
- foreach ($dirs as $dir) {
- if (is_dir($this->path . '/' . $dir)) {
- rmdir($this->path . '/' . $dir);
- }
- }
- }
-
- public function testGetSubscribedEvents()
- {
- $expected = [
- 'post-autoload-dump' => 'postAutoloadDump',
- ];
-
- $this->assertSame($expected, $this->plugin->getSubscribedEvents());
- }
-
- public function testGetConfigFilePath()
- {
- $path = $this->plugin->getConfigFilePath('');
- $this->assertFileExists(dirname($path));
- }
-
- public function testGetPrimaryNamespace()
- {
- $autoload = [
- 'psr-4' => [
- 'FOC\\Authenticate' => '',
- ],
- ];
- $this->package->setAutoload($autoload);
-
- $ns = $this->plugin->getPrimaryNamespace($this->package);
- $this->assertEquals('FOC\Authenticate', $ns);
-
- $autoload = [
- 'psr-4' => [
- 'FOC\Acl\Test' => './tests',
- 'FOC\Acl' => '',
- ],
- ];
- $this->package->setAutoload($autoload);
- $ns = $this->plugin->getPrimaryNamespace($this->package);
- $this->assertEquals('FOC\Acl', $ns);
-
- $autoload = [
- 'psr-4' => [
- 'Foo\Bar' => 'foo',
- 'Acme\Plugin' => './src',
- ],
- ];
- $this->package->setAutoload($autoload);
- $ns = $this->plugin->getPrimaryNamespace($this->package);
- $this->assertEquals('Acme\Plugin', $ns);
-
- $autoload = [
- 'psr-4' => [
- 'Foo\Bar' => 'bar',
- 'Foo\\' => '',
- ],
- ];
- $this->package->setAutoload($autoload);
- $ns = $this->plugin->getPrimaryNamespace($this->package);
- $this->assertEquals('Foo', $ns);
-
- $autoload = [
- 'psr-4' => [
- 'Foo\Bar' => 'bar',
- 'Foo' => '.',
- ],
- ];
- $this->package->setAutoload($autoload);
- $ns = $this->plugin->getPrimaryNamespace($this->package);
- $this->assertEquals('Foo', $ns);
-
- $autoload = [
- 'psr-4' => [
- 'Acme\Foo\Bar' => 'bar',
- 'Acme\Foo\\' => '',
- ],
- ];
- $this->package->setAutoload($autoload);
- $ns = $this->plugin->getPrimaryNamespace($this->package);
- $this->assertEquals('Acme\Foo', $ns);
-
- $autoload = [
- 'psr-4' => [
- 'Acme\Foo\Bar' => '',
- 'Acme\Foo' => 'src',
- ],
- ];
- $this->package->setAutoload($autoload);
- $name = $this->plugin->getPrimaryNamespace($this->package);
- $this->assertEquals('Acme\Foo', $name);
- }
-
- public function testFindPlugins()
- {
- $plugin1 = new Package('cakephp/the-thing', '1.0', '1.0');
- $plugin1->setType('cakephp-plugin');
- $plugin1->setAutoload([
- 'psr-4' => [
- 'TheThing' => 'src/',
- ],
- ]);
-
- $plugin2 = new Package('cakephp/princess', '1.0', '1.0');
- $plugin2->setType('cakephp-plugin');
- $plugin2->setAutoload([
- 'psr-4' => [
- 'Princess' => 'src/',
- ],
- ]);
-
- $packages = [
- $plugin1,
- new Package('SomethingElse', '1.0', '1.0'),
- $plugin2,
- ];
-
- $return = $this->plugin->findPlugins(
- $packages,
- [$this->path . '/doesnt-exist'],
- $this->path . '/vendor'
- );
-
- $expected = [
- 'Princess' => $this->path . '/vendor/cakephp/princess',
- 'TheThing' => $this->path . '/vendor/cakephp/the-thing',
- ];
- $this->assertSame($expected, $return, 'Only composer-loaded plugins should be listed');
-
- $return = $this->plugin->findPlugins(
- $packages,
- [$this->path . '/plugins'],
- $this->path . '/vendor'
- );
-
- $expected = [
- 'Fee' => $this->path . '/plugins/Fee',
- 'Foe' => $this->path . '/plugins/Foe',
- 'Foo' => $this->path . '/plugins/Foo',
- 'Fum' => $this->path . '/plugins/Fum',
- 'Princess' => $this->path . '/vendor/cakephp/princess',
- 'TheThing' => $this->path . '/vendor/cakephp/the-thing',
- ];
- $this->assertSame($expected, $return, 'Composer and application plugins should be listed');
-
- $return = $this->plugin->findPlugins(
- $packages,
- [$this->path . '/plugins', $this->path . '/app_plugins'],
- $this->path . '/vendor'
- );
-
- $expected = [
- 'Bar' => $this->path . '/app_plugins/Bar',
- 'Fee' => $this->path . '/plugins/Fee',
- 'Foe' => $this->path . '/plugins/Foe',
- 'Foo' => $this->path . '/plugins/Foo',
- 'Fum' => $this->path . '/plugins/Fum',
- 'Princess' => $this->path . '/vendor/cakephp/princess',
- 'TheThing' => $this->path . '/vendor/cakephp/the-thing',
- ];
- $this->assertSame($expected, $return, 'Composer and application plugins should be listed');
- }
-
- public function testWriteConfigFile()
- {
- $plugins = [
- 'Fee' => $this->path . '/plugins/Fee',
- 'Foe' => $this->path . '/plugins/Foe',
- 'Foo' => $this->path . '/plugins/Foo',
- 'Fum' => $this->path . '/plugins/Fum',
- 'OddOneOut' => '/some/other/path',
- 'Princess' => $this->path . '/vendor/cakephp/princess',
- 'TheThing' => $this->path . '/vendor/cakephp/the-thing',
- 'Vendor\Plugin' => $this->path . '/vendor/vendor/plugin',
- ];
-
- $path = $this->path . '/vendor/cakephp-plugins.php';
- $this->plugin->writeConfigFile($path, $plugins);
-
- $this->assertFileExists($path);
- $contents = file_get_contents($path);
-
- $this->assertStringContainsString('assertStringContainsString('$baseDir = dirname(dirname(__FILE__));', $contents);
- $this->assertStringContainsString(
- "'Fee' => \$baseDir . '/plugins/Fee/'",
- $contents,
- 'paths should be relative for app-plugins'
- );
- $this->assertStringContainsString(
- "'Princess' => \$baseDir . '/vendor/cakephp/princess/'",
- $contents,
- 'paths should be relative for vendor-plugins'
- );
- $this->assertStringContainsString(
- "'OddOneOut' => '/some/other/path/'",
- $contents,
- 'paths should stay absolute if it\'s not under the application root'
- );
- $this->assertStringContainsString(
- "'Vendor/Plugin' => \$baseDir . '/vendor/vendor/plugin/'",
- $contents,
- 'Plugin namespaces should use forward slash'
- );
-
- // Ensure all plugin paths are slash terminated
- foreach ($plugins as &$plugin) {
- $plugin .= '/';
- }
- unset($plugin);
-
- $result = require $path;
- $expected = [
- 'plugins' => $plugins,
- ];
- $expected['plugins']['Vendor/Plugin'] = $expected['plugins']['Vendor\Plugin'];
- unset($expected['plugins']['Vendor\Plugin']);
-
- $this->assertSame(
- $expected,
- $result,
- 'The evaluated result should be the same as the input except for namespaced plugin'
- );
- }
-}