diff --git a/.gitignore b/.gitignore index f2db597..05006ec 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ composer.lock vendor phpunit.xml clover.xml +.phpunit.result.cache +.idea/ diff --git a/.travis.yml b/.travis.yml index 329b5b9..0fa480e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,15 +1,11 @@ language: php -matrix: - include: - - php: 5.3 - dist: precise php: - - '5.4' - - '5.5' - '5.6' - '7.0' - '7.1' - '7.2' + - '7.3' + - '7.4' before_script: - composer update script: composer test diff --git a/README.md b/README.md index 0dbbab5..62c0026 100644 --- a/README.md +++ b/README.md @@ -16,16 +16,18 @@ For more information on this site setup and using Composer to manage a whole Wor ### Usage To set up a custom WordPress build package to use this as a custom installer, add the following to your package's composer file: -``` +```json "type": "wordpress-core", "require": { - "roots/wordpress-core-installer": "^1.0" + "roots/wordpress-core-installer": "^2.0" } ``` +If you need to maintain support for PHP versions lower than 5.6 (not recommended!), use `^1.0` as your version constraint in the above. + By default, this package will install a `wordpress-core` type package in the `wordpress` directory. To change this you can add the following to either your custom WordPress core type package or the root composer package: -``` +```json "extra": { "wordpress-install-dir": "custom/path" } @@ -33,7 +35,7 @@ By default, this package will install a `wordpress-core` type package in the `wo The root composer package can also declare custom paths as an object keyed by package name: -``` +```json "extra": { "wordpress-install-dir": { "wordpress/wordpress": "wordpress", @@ -44,3 +46,16 @@ The root composer package can also declare custom paths as an object keyed by pa ### License This is licensed under the GPL version 2 or later. + +### Changelog + +##### 2.0.0 +- Added support for Composer v2. Special thanks to @Ayesh for the original pull request to add this support. +- Bumped minimum required PHP version to 5.6 (same as WP). If you need to stick with an older PHP version, you're probably ok with also sticking with an older version of Composer and can continue to use `^1.0` as your version constraint. +- Other various fixes and improvements to README, tests, etc. + +##### 1.0.0 +- Initial stable release +- Added tests and CI +- Support added for custom vendor directories +- Added sanity check for overwriting sensitive directories diff --git a/composer.json b/composer.json index e244a8f..7f1b694 100644 --- a/composer.json +++ b/composer.json @@ -32,11 +32,12 @@ "class": "Roots\\Composer\\WordPressCorePlugin" }, "require": { - "composer-plugin-api": "^1.0" + "composer-plugin-api": "^1.0 || ^2.0", + "php": ">=5.6.0" }, "require-dev": { - "composer/composer": "^1.0", - "phpunit/phpunit": ">=4.8.35" + "composer/composer": "^1.0 || ^2.0", + "phpunit/phpunit": ">=5.7.27" }, "conflict": { "composer/installers": "<1.0.6" diff --git a/src/WordPressCorePlugin.php b/src/WordPressCorePlugin.php index 90a7126..2481b8f 100644 --- a/src/WordPressCorePlugin.php +++ b/src/WordPressCorePlugin.php @@ -38,4 +38,16 @@ public function activate( Composer $composer, IOInterface $io ) { $composer->getInstallationManager()->addInstaller( $installer ); } + /** + * {@inheritDoc} + */ + public function deactivate( Composer $composer, IOInterface $io ) { + } + + /** + * {@inheritDoc} + */ + public function uninstall( Composer $composer, IOInterface $io ) { + } + } diff --git a/tests/phpunit/WordPressCoreInstallerTest.php b/tests/phpunit/WordPressCoreInstallerTest.php index bb8d276..c20cb04 100644 --- a/tests/phpunit/WordPressCoreInstallerTest.php +++ b/tests/phpunit/WordPressCoreInstallerTest.php @@ -29,162 +29,188 @@ use Roots\Composer\WordPressCoreInstaller; use PHPUnit\Framework\TestCase; -class WordPressCoreInstallerTest extends TestCase { - - protected function setUp() { - $this->resetInstallPaths(); - } - - protected function tearDown() { - $this->resetInstallPaths(); - } - - public function testSupports() { - $installer = new WordPressCoreInstaller( new NullIO(), $this->createComposer() ); - - $this->assertTrue( $installer->supports( 'wordpress-core' ) ); - $this->assertFalse( $installer->supports( 'not-wordpress-core' ) ); - } - - public function testDefaultInstallDir() { - $installer = new WordPressCoreInstaller( new NullIO(), $this->createComposer() ); - $package = new Package( 'johnpbloch/test-package', '1.0.0.0', '1.0.0' ); - - $this->assertEquals( 'wordpress', $installer->getInstallPath( $package ) ); - } - - public function testSingleRootInstallDir() { - $composer = $this->createComposer(); - $rootPackage = new RootPackage( 'test/root-package', '1.0.1.0', '1.0.1' ); - $composer->setPackage( $rootPackage ); - $installDir = 'tmp-wp-' . rand( 0, 9 ); - $rootPackage->setExtra( array( - 'wordpress-install-dir' => $installDir, - ) ); - $installer = new WordPressCoreInstaller( new NullIO(), $composer ); - - $this->assertEquals( - $installDir, - $installer->getInstallPath( - new Package( 'not/important', '1.0.0.0', '1.0.0' ) - ) - ); - } - - public function testArrayOfInstallDirs() { - $composer = $this->createComposer(); - $rootPackage = new RootPackage( 'test/root-package', '1.0.1.0', '1.0.1' ); - $composer->setPackage( $rootPackage ); - $rootPackage->setExtra( array( - 'wordpress-install-dir' => array( - 'test/package-one' => 'install-dir/one', - 'test/package-two' => 'install-dir/two', - ), - ) ); - $installer = new WordPressCoreInstaller( new NullIO(), $composer ); - - $this->assertEquals( - 'install-dir/one', - $installer->getInstallPath( - new Package( 'test/package-one', '1.0.0.0', '1.0.0' ) - ) - ); - - $this->assertEquals( - 'install-dir/two', - $installer->getInstallPath( - new Package( 'test/package-two', '1.0.0.0', '1.0.0' ) - ) - ); - } - - public function testCorePackageCanDefineInstallDirectory() { - $installer = new WordPressCoreInstaller( new NullIO(), $this->createComposer() ); - $package = new Package( 'test/has-default-install-dir', '0.1.0.0', '0.1' ); - $package->setExtra( array( - 'wordpress-install-dir' => 'not-wordpress', - ) ); - - $this->assertEquals( 'not-wordpress', $installer->getInstallPath( $package ) ); - } - - public function testCorePackageDefaultDoesNotOverrideRootDirectoryDefinition() { - $composer = $this->createComposer(); - $composer->setPackage( new RootPackage( 'test/root-package', '0.1.0.0', '0.1' ) ); - $composer->getPackage()->setExtra( array( - 'wordpress-install-dir' => 'wp', - ) ); - $installer = new WordPressCoreInstaller( new NullIO(), $composer ); - $package = new Package( 'test/has-default-install-dir', '0.1.0.0', '0.1' ); - $package->setExtra( array( - 'wordpress-install-dir' => 'not-wordpress', - ) ); - - $this->assertEquals( 'wp', $installer->getInstallPath( $package ) ); - } - - /** - * @expectedException \InvalidArgumentException - * @expectedExceptionMessage Two packages (test/bazbat and test/foobar) cannot share the same directory! - */ - public function testTwoPackagesCannotShareDirectory() { - $composer = $this->createComposer(); - $installer = new WordPressCoreInstaller( new NullIO(), $composer ); - $package1 = new Package( 'test/foobar', '1.1.1.1', '1.1.1.1' ); - $package2 = new Package( 'test/bazbat', '1.1.1.1', '1.1.1.1' ); - - $installer->getInstallPath( $package1 ); - $installer->getInstallPath( $package2 ); - } - - public function testTwoPackagesCannotShareDirectoryUnlessWpCoreType() { - $composer = $this->createComposer(); - $installer = new WordPressCoreInstaller( new NullIO(), $composer ); - $package1 = new Package( 'johnpbloch/wordpress', '4.9.8', '4.9.8' ); - $package1->setType('wordpress-core'); - $package2 = new Package( 'roots/wordpress', '5.0', '5.0' ); - $package2->setType('wordpress-core'); - - $installer->getInstallPath( $package1 ); - $installer->getInstallPath( $package2 ); - - $this->assertTrue(true); // no exceptions thrown - } - - /** - * @dataProvider dataProviderSensitiveDirectories - * @expectedException \InvalidArgumentException - * @expectedExceptionMessageRegExp /Warning! .+? is an invalid WordPress install directory \(from test\/package\)!/ - */ - public function testSensitiveInstallDirectoriesNotAllowed( $directory ) { - $composer = $this->createComposer(); - $installer = new WordPressCoreInstaller( new NullIO(), $composer ); - $package = new Package( 'test/package', '1.1.0.0', '1.1' ); - $package->setExtra( array( 'wordpress-install-dir' => $directory ) ); - $installer->getInstallPath( $package ); - } - - public function dataProviderSensitiveDirectories() { - return array( - array( '.' ), - array( 'vendor' ), - ); - } - - private function resetInstallPaths() { - $prop = new \ReflectionProperty( '\Roots\Composer\WordPressCoreInstaller', '_installedPaths' ); - $prop->setAccessible( true ); - $prop->setValue( array() ); - } - - /** - * @return Composer - */ - private function createComposer() { - $composer = new Composer(); - $composer->setConfig( new Config() ); - - return $composer; - } - +class WordPressCoreInstallerTest extends TestCase +{ + public function testSupports() + { + $installer = new WordPressCoreInstaller(new NullIO(), $this->createComposer()); + + $this->assertTrue($installer->supports('wordpress-core')); + $this->assertFalse($installer->supports('not-wordpress-core')); + } + + public function testDefaultInstallDir() + { + $installer = new WordPressCoreInstaller(new NullIO(), $this->createComposer()); + $package = new Package('johnpbloch/test-package', '1.0.0.0', '1.0.0'); + + $this->assertEquals('wordpress', $installer->getInstallPath($package)); + } + + public function testSingleRootInstallDir() + { + $composer = $this->createComposer(); + $rootPackage = new RootPackage('test/root-package', '1.0.1.0', '1.0.1'); + $composer->setPackage($rootPackage); + $installDir = 'tmp-wp-' . rand(0, 9); + $rootPackage->setExtra(array( + 'wordpress-install-dir' => $installDir, + )); + $installer = new WordPressCoreInstaller(new NullIO(), $composer); + + $this->assertEquals( + $installDir, + $installer->getInstallPath( + new Package('not/important', '1.0.0.0', '1.0.0') + ) + ); + } + + public function testArrayOfInstallDirs() + { + $composer = $this->createComposer(); + $rootPackage = new RootPackage('test/root-package', '1.0.1.0', '1.0.1'); + $composer->setPackage($rootPackage); + $rootPackage->setExtra(array( + 'wordpress-install-dir' => array( + 'test/package-one' => 'install-dir/one', + 'test/package-two' => 'install-dir/two', + ), + )); + $installer = new WordPressCoreInstaller(new NullIO(), $composer); + + $this->assertEquals( + 'install-dir/one', + $installer->getInstallPath( + new Package('test/package-one', '1.0.0.0', '1.0.0') + ) + ); + + $this->assertEquals( + 'install-dir/two', + $installer->getInstallPath( + new Package('test/package-two', '1.0.0.0', '1.0.0') + ) + ); + } + + public function testCorePackageCanDefineInstallDirectory() + { + $installer = new WordPressCoreInstaller(new NullIO(), $this->createComposer()); + $package = new Package('test/has-default-install-dir', '0.1.0.0', '0.1'); + $package->setExtra(array( + 'wordpress-install-dir' => 'not-wordpress', + )); + + $this->assertEquals('not-wordpress', $installer->getInstallPath($package)); + } + + public function testCorePackageDefaultDoesNotOverrideRootDirectoryDefinition() + { + $composer = $this->createComposer(); + $composer->setPackage(new RootPackage('test/root-package', '0.1.0.0', '0.1')); + $composer->getPackage()->setExtra(array( + 'wordpress-install-dir' => 'wp', + )); + $installer = new WordPressCoreInstaller(new NullIO(), $composer); + $package = new Package('test/has-default-install-dir', '0.1.0.0', '0.1'); + $package->setExtra(array( + 'wordpress-install-dir' => 'not-wordpress', + )); + + $this->assertEquals('wp', $installer->getInstallPath($package)); + } + + public function testTwoPackagesCannotShareDirectory() + { + $this->jpbExpectException( + '\InvalidArgumentException', + 'Two packages (test/bazbat and test/foobar) cannot share the same directory!' + ); + $composer = $this->createComposer(); + $installer = new WordPressCoreInstaller(new NullIO(), $composer); + $package1 = new Package('test/foobar', '1.1.1.1', '1.1.1.1'); + $package2 = new Package('test/bazbat', '1.1.1.1', '1.1.1.1'); + + $installer->getInstallPath($package1); + $installer->getInstallPath($package2); + } + + public function testTwoPackagesCannotShareDirectoryUnlessWpCoreType() + { + $composer = $this->createComposer(); + $installer = new WordPressCoreInstaller(new NullIO(), $composer); + $package1 = new Package('johnpbloch/wordpress', '4.9.8', '4.9.8'); + $package1->setType('wordpress-core'); + $package2 = new Package('roots/wordpress', '5.0', '5.0'); + $package2->setType('wordpress-core'); + + $installer->getInstallPath($package1); + $installer->getInstallPath($package2); + + $this->assertTrue(true); // no exceptions thrown + } + + /** + * @dataProvider dataProviderSensitiveDirectories + */ + public function testSensitiveInstallDirectoriesNotAllowed($directory) + { + $this->jpbExpectException( + '\InvalidArgumentException', + '/Warning! .+? is an invalid WordPress install directory \(from test\/package\)!/', + true + ); + $composer = $this->createComposer(); + $installer = new WordPressCoreInstaller(new NullIO(), $composer); + $package = new Package('test/package', '1.1.0.0', '1.1'); + $package->setExtra(array( 'wordpress-install-dir' => $directory )); + $installer->getInstallPath($package); + } + + public function dataProviderSensitiveDirectories() + { + return array( + array( '.' ), + array( 'vendor' ), + ); + } + + /** + * @before + * @afterClass + */ + public static function resetInstallPaths() + { + $prop = new \ReflectionProperty('\Roots\Composer\WordPressCoreInstaller', '_installedPaths'); + $prop->setAccessible(true); + $prop->setValue(array()); + } + + /** + * @return Composer + */ + private function createComposer() + { + $composer = new Composer(); + $composer->setConfig(new Config()); + + return $composer; + } + + private function jpbExpectException($class, $message = '', $isRegExp = false) + { + $this->expectException($class); + if ($message) { + if ($isRegExp) { + if (method_exists($this, 'expectExceptionMessageRegExp')) { + $this->expectExceptionMessageRegExp($message); + } else { + $this->expectExceptionMessageMatches($message); + } + } else { + $this->expectExceptionMessage($message); + } + } + } } diff --git a/tests/phpunit/WordPressCorePluginTest.php b/tests/phpunit/WordPressCorePluginTest.php index 8b7a3dc..f0244d0 100644 --- a/tests/phpunit/WordPressCorePluginTest.php +++ b/tests/phpunit/WordPressCorePluginTest.php @@ -24,24 +24,55 @@ use Composer\Composer; use Composer\Config; use Composer\Installer\InstallationManager; +use Composer\IO\IOInterface; use Composer\IO\NullIO; +use Composer\Plugin\PluginInterface; +use Composer\Test\Mock\HttpDownloaderMock; +use Composer\Util\HttpDownloader; +use Composer\Util\Loop; use Roots\Composer\WordPressCorePlugin; use PHPUnit\Framework\TestCase; -class WordPressCorePluginTest extends TestCase { +class WordPressCorePluginTest extends TestCase +{ + public function testActivate() + { + $composer = new Composer(); + $composer->setConfig(new Config()); + $nullIO = new NullIO(); + $installationManager = $this->getInstallationManager($composer, $nullIO); + $composer->setInstallationManager($installationManager); + $composer->setConfig(new Config()); - public function testActivate() { - $composer = new Composer(); - $installationManager = new InstallationManager(); - $composer->setInstallationManager( $installationManager ); - $composer->setConfig( new Config() ); + $plugin = new WordPressCorePlugin(); + $plugin->activate($composer, $nullIO); - $plugin = new WordPressCorePlugin(); - $plugin->activate( $composer, new NullIO() ); + $installer = $installationManager->getInstaller('wordpress-core'); - $installer = $installationManager->getInstaller( 'wordpress-core' ); + $this->assertInstanceOf('\Roots\Composer\WordPressCoreInstaller', $installer); + } - $this->assertInstanceOf( '\Roots\Composer\WordPressCoreInstaller', $installer ); - } + /** + * @param Composer $composer + * @param IOInterface $io + * + * @return InstallationManager + */ + private function getInstallationManager($composer, $io) + { + $installationManager = null; + switch (explode('.', PluginInterface::PLUGIN_API_VERSION)[0]) { + case '1': + $installationManager = new InstallationManager(); + break; + case '2': + default: + $http = new HttpDownloader($io, $composer->getConfig()); + $loop = new Loop($http); + $installationManager = new InstallationManager($loop, $io); + break; + } + return $installationManager; + } }