From 445f575bc0e4f13d29a37ea98b1a7d211562b092 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20H=C3=A4u=C3=9Fler?= Date: Fri, 8 Jan 2021 16:40:52 +0100 Subject: [PATCH 1/7] [FEATURE] Add support for PHP 7.4 and PHP 8.0 --- Readme.md | 31 ++++++++++--------- composer.json | 13 ++++---- src/Installer.php | 15 +++++---- src/Reflection/PackageVersions.php | 13 +++++++- tests/InstalledPackagesTraitTest.php | 12 +++---- tests/Unit/Dto/PackageTest.php | 14 ++++----- .../BundleDescriberClassGeneratorTest.php | 6 ++-- tests/Unit/InstallerTest.php | 2 +- tests/Unit/Reflection/InstallPathTest.php | 5 +-- tests/Unit/Reflection/PackageVersionsTest.php | 4 +-- .../Reflection/RootPackageReflectionTest.php | 8 +++-- 11 files changed, 71 insertions(+), 52 deletions(-) diff --git a/Readme.md b/Readme.md index 44d28ce..2b83ad7 100644 --- a/Readme.md +++ b/Readme.md @@ -1,30 +1,31 @@ -Auditor -========= +# Auditor -This is a composer plugin. It allows to access information about the current (root) package. +This is a Composer plugin. It allows to access information about the current (root) package. -### Requirements -* composer +## Requirements + +* Composer * PHP >= 7.1 -### Usage +### Version matrix + +| | PHP 8.0 | PHP 7.4 | PHP 7.3 | PHP 7.2 | PHP 7.1 | +| ------------ | ------- | ------- | ------- | ------- | ------- | +| Composer 1.x | :x: | 0.5.x | 0.5.x | 0.1.0 - 0.5.x | 0.1.0 - 0.5.x +| Composer 2.x | 0.5.x | 0.5.x | :x: | :x: | :x: | + +## Usage In your project root -````bash +```bash composer require cpsit/auditor -```` - -**Note:** The package is not yet available on packagist.org. -Please add `https://github.com/CPS-IT/auditor` to the list of repositories in your -`composer.json` +``` -After installation or update via composer a class `CPSIT\Auditor\BundleDescriber` is generated. +After installation or update via Composer a class `CPSIT\Auditor\BundleDescriber` is generated. It allows to access each property of your bundle (root package). ```php $name = \CPSIT\Auditor\BundleDescriber::getProperty('name'); - ``` - diff --git a/composer.json b/composer.json index d2bbafa..0e37a95 100644 --- a/composer.json +++ b/composer.json @@ -4,9 +4,9 @@ "license": "GPL-2.0-or-later", "type": "composer-plugin", "require": { - "php": ">=7.0.0 <=7.3.0", - "composer-plugin-api": "^1.0.0", - "ocramius/package-versions": "^1.3.0" + "php": "^7.1.0 || ~8.0.0", + "composer-plugin-api": "^1.0.0 || ^2.0.0", + "ocramius/package-versions": "^1.3.0 || ^2.0.0" }, "authors": [ { @@ -21,11 +21,12 @@ "scripts": { "post-autoload-dump": [ "mkdir -p .build/log/coverage/" - ] + ], + "test": "phpunit -c tests/Build/UnitTests.xml" }, "require-dev": { - "phpunit/phpunit": "^6.5.0 || ^7.0.0", - "composer/composer": "^1.6.3" + "phpunit/phpunit": "^7.5.0 || ^8.0.0 || ^9.0.0", + "composer/composer": "^1.6.3 || ^2.0.0" }, "autoload": { "psr-4": { diff --git a/src/Installer.php b/src/Installer.php index 0e9f9db..87a0567 100644 --- a/src/Installer.php +++ b/src/Installer.php @@ -20,19 +20,13 @@ ***************************************************************/ use Composer\Composer; -use Composer\Config; use Composer\EventDispatcher\EventSubscriberInterface; use Composer\IO\IOInterface; -use Composer\Package\AliasPackage; -use Composer\Package\Locker; -use Composer\Package\PackageInterface; -use Composer\Package\RootPackageInterface; use Composer\Plugin\PluginInterface; use Composer\Script\Event; use Composer\Script\ScriptEvents; use CPSIT\Auditor\Generator\BundleDescriberClassGenerator; use CPSIT\Auditor\Reflection\RootPackageReflection; -use CPSIT\Auditor\SettingsInterface as SI; /** * Class Installer @@ -73,4 +67,13 @@ public static function dumpBundleDescriberClass(Event $composerEvent) $generator->writeFile($properties, $installedPackages); } + public function deactivate(Composer $composer, IOInterface $io): void + { + // Intentionally left blank. + } + + public function uninstall(Composer $composer, IOInterface $io): void + { + // Intentionally left blank. + } } diff --git a/src/Reflection/PackageVersions.php b/src/Reflection/PackageVersions.php index 2a4a2df..8b02b40 100644 --- a/src/Reflection/PackageVersions.php +++ b/src/Reflection/PackageVersions.php @@ -18,6 +18,8 @@ * GNU General Public License for more details. * This copyright notice MUST APPEAR in all copies of the script! ***************************************************************/ + +use Composer\InstalledVersions; use CPSIT\Auditor\Dto\Package; use PackageVersions\Versions; @@ -31,7 +33,7 @@ class PackageVersions public static function getAll($versions = []) { if (empty($versions)) { - $versions = Versions::VERSIONS; + $versions = static::parsePackageVersions(); } $packages = []; @@ -50,4 +52,13 @@ public static function getAll($versions = []) return $packages; } + + private static function parsePackageVersions(): array + { + if (defined(Versions::class . '::VERSIONS')) { + return Versions::VERSIONS; + } + $packages = InstalledVersions::getInstalledPackages(); + return array_map([Versions::class, 'getVersion'], $packages); + } } diff --git a/tests/InstalledPackagesTraitTest.php b/tests/InstalledPackagesTraitTest.php index 80053d1..47004a4 100644 --- a/tests/InstalledPackagesTraitTest.php +++ b/tests/InstalledPackagesTraitTest.php @@ -53,20 +53,20 @@ class InstalledPackagesTraitTest extends TestCase 'foo' => ['bar'] ]; - public function setUp() + public function setUp(): void { $this->subject = $this->getMockBuilder(InstalledPackagesTrait::class) ->getMockForTrait(); } - public function testGetInstalledPackagesReturnsArray() + public function testGetInstalledPackagesReturnsArray(): void { $this->assertIsArray( $this->subject::getInstalledPackages() ); } - public function testIsPackageInstalledReturnsTrueForInstalledPackage() + public function testIsPackageInstalledReturnsTrueForInstalledPackage(): void { $this->assertTrue( MockClassWithInstalledPackages::isPackageInstalled('foo') @@ -76,7 +76,7 @@ public function testIsPackageInstalledReturnsTrueForInstalledPackage() /** * @covers ::isPackageInstalled */ - public function testIsPackageInstalledReturnsFalseForMissingPackage() + public function testIsPackageInstalledReturnsFalseForMissingPackage(): void { $this->assertFalse( MockClassWithInstalledPackages::isPackageInstalled('anyPackageName') @@ -88,7 +88,7 @@ public function testIsPackageInstalledReturnsFalseForMissingPackage() * @expectedException \OutOfBoundsException * @expextedExceptionCode 1557047757 */ - public function testPropertyExistThrowsExceptionForMissingProperty() + public function testPropertyExistThrowsExceptionForMissingProperty(): void { $expectedMessage = sprintf( DescriberInterface::ERROR_MISSING_PROPERTY, @@ -110,7 +110,7 @@ public function testPropertyExistThrowsExceptionForMissingProperty() /** * @covers ::getInstalledPackage */ - public function testGetInstalledPackageReturnsPackageObject() + public function testGetInstalledPackageReturnsPackageObject(): void { $this->assertInstanceOf( Package::class, diff --git a/tests/Unit/Dto/PackageTest.php b/tests/Unit/Dto/PackageTest.php index cb810b5..77cb826 100644 --- a/tests/Unit/Dto/PackageTest.php +++ b/tests/Unit/Dto/PackageTest.php @@ -32,13 +32,13 @@ class PackageTest extends TestCase /** * @inheritdoc */ - public function setUp()/* The :void return type declaration that should be here would cause a BC issue */ + public function setUp(): void { parent::setUp(); $this->subject = new Package(); } - public function testVersionIsInitiallyEmptyString() + public function testVersionIsInitiallyEmptyString(): void { $this->assertSame( '', @@ -46,7 +46,7 @@ public function testVersionIsInitiallyEmptyString() ); } - public function testVersionCanBeSet() + public function testVersionCanBeSet(): void { $value = 'foo'; $this->subject->setVersion($value); @@ -57,7 +57,7 @@ public function testVersionCanBeSet() ); } - public function testNameIsInitiallyEmptyString() + public function testNameIsInitiallyEmptyString(): void { $this->assertSame( '', @@ -65,7 +65,7 @@ public function testNameIsInitiallyEmptyString() ); } - public function testNameCanBeSet() + public function testNameCanBeSet(): void { $value = 'foo'; $this->subject->setName($value); @@ -76,7 +76,7 @@ public function testNameCanBeSet() ); } - public function testSourceReferenceIsInitiallyEmptyString() + public function testSourceReferenceIsInitiallyEmptyString(): void { $this->assertSame( '', @@ -84,7 +84,7 @@ public function testSourceReferenceIsInitiallyEmptyString() ); } - public function testSourceReferenceCanBeSet() + public function testSourceReferenceCanBeSet(): void { $value = 'foo'; $this->subject->setSourceReference($value); diff --git a/tests/Unit/Generator/BundleDescriberClassGeneratorTest.php b/tests/Unit/Generator/BundleDescriberClassGeneratorTest.php index 2214ac1..9f245f1 100644 --- a/tests/Unit/Generator/BundleDescriberClassGeneratorTest.php +++ b/tests/Unit/Generator/BundleDescriberClassGeneratorTest.php @@ -49,7 +49,7 @@ class BundleDescriberClassGeneratorTest extends TestCase /** * {@inheritDoc) */ - public function setUp()/* The :void return type declaration that should be here would cause a BC issue */ + public function setUp(): void { parent::setUp(); $this->composer = $this->getMockBuilder(Composer::class) @@ -68,7 +68,7 @@ public function setUp()/* The :void return type declaration that should be here /** * @test */ - public function writeFileWritesMessageForMissingFilePath() + public function writeFileWritesMessageForMissingFilePath(): void { $invalidFilePath = '/bar/baz.boo'; @@ -88,7 +88,7 @@ public function writeFileWritesMessageForMissingFilePath() /** * @test */ - public function writeFileWritesMessageAfterGeneration() + public function writeFileWritesMessageAfterGeneration(): void { $this->markTestSkipped(); $invalidFilePath = 'bar/'; diff --git a/tests/Unit/InstallerTest.php b/tests/Unit/InstallerTest.php index 0179fa7..a26da78 100644 --- a/tests/Unit/InstallerTest.php +++ b/tests/Unit/InstallerTest.php @@ -58,7 +58,7 @@ public function testGetSubscribedEvents(): void $events ); foreach ($events as $callback) { - self::assertInternalType('callable', [$this->subject, $callback]); + self::assertIsCallable([$this->subject, $callback]); } } diff --git a/tests/Unit/Reflection/InstallPathTest.php b/tests/Unit/Reflection/InstallPathTest.php index 59c879b..cf05889 100644 --- a/tests/Unit/Reflection/InstallPathTest.php +++ b/tests/Unit/Reflection/InstallPathTest.php @@ -50,7 +50,7 @@ class InstallPathTest extends TestCase /** * {@inheritdoc} */ - public function setUp()/* The :void return type declaration that should be here would cause a BC issue */ + public function setUp(): void { parent::setUp(); $this->composerConfig = $this->getMockBuilder(Config::class) @@ -68,7 +68,8 @@ public function setUp()/* The :void return type declaration that should be here /** * @test */ - public function testToStringReturnsPackagePathInVendorFolderFromComposerConfig() { + public function testToStringReturnsPackagePathInVendorFolderFromComposerConfig(): void + { $vendorDir = 'foo'; $expectedPath = $vendorDir . '/' . SI::PACKAGE_IDENTIFIER; diff --git a/tests/Unit/Reflection/PackageVersionsTest.php b/tests/Unit/Reflection/PackageVersionsTest.php index 54c8c4b..4c7ffe3 100644 --- a/tests/Unit/Reflection/PackageVersionsTest.php +++ b/tests/Unit/Reflection/PackageVersionsTest.php @@ -24,14 +24,14 @@ class PackageVersionsTest extends TestCase { - public function testGetAllReturnsArray() + public function testGetAllReturnsArray(): void { $this->assertIsArray( PackageVersions::getAll() ); } - public function testGetAllReturnsPackagesArray() + public function testGetAllReturnsPackagesArray(): void { $name = 'composer/ca-bundle'; $version = '1.1.3'; diff --git a/tests/Unit/Reflection/RootPackageReflectionTest.php b/tests/Unit/Reflection/RootPackageReflectionTest.php index 401bbf9..46d4b71 100644 --- a/tests/Unit/Reflection/RootPackageReflectionTest.php +++ b/tests/Unit/Reflection/RootPackageReflectionTest.php @@ -36,7 +36,7 @@ class RootPackageReflectionTest extends TestCase */ protected $rootPackage; - public function setUp() + public function setUp(): void { parent::setUp(); // TODO: Change the autogenerated stub $this->rootPackage = $this->getMockBuilder(RootPackageInterface::class) @@ -46,7 +46,8 @@ public function setUp() /** * @test */ - public function testGetPropertiesReturnsArray(){ + public function testGetPropertiesReturnsArray(): void + { $result = RootPackageReflection::getProperties($this->rootPackage); $this->assertTrue( @@ -57,7 +58,8 @@ public function testGetPropertiesReturnsArray(){ /** * @test */ - public function testGetPropertiesContainsAllowedProperties(){ + public function testGetPropertiesContainsAllowedProperties(): void + { $expectedProperties = RootPackageReflectionInterface::SUPPORTED_PACKAGE_PROPERTIES; $result = RootPackageReflection::getProperties($this->rootPackage); From 4853b1e03beb917bba309ef220aa9f4963a75ed4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20H=C3=A4u=C3=9Fler?= Date: Fri, 8 Jan 2021 16:41:14 +0100 Subject: [PATCH 2/7] [TASK] Introduce GitHub actions for testing --- .github/workflows/tests.yaml | 63 +++++++++++++++++++ .travis.yml | 30 ++++----- ...ect.properties => sonar-project.properties | 0 3 files changed, 78 insertions(+), 15 deletions(-) create mode 100644 .github/workflows/tests.yaml rename .sonar-project.properties => sonar-project.properties (100%) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml new file mode 100644 index 0000000..cff67c4 --- /dev/null +++ b/.github/workflows/tests.yaml @@ -0,0 +1,63 @@ +name: Tests +on: [push, pull_request] + +jobs: + tests: + name: PHP ${{ matrix.php-version }} & Composer ${{ matrix.composer-version }} + + runs-on: ubuntu-18.04 + strategy: + fail-fast: false + matrix: + include: + # Composer 2.x + - php-version: 8.0 + composer-version: 2 + - php-version: 7.4 + composer-version: 2 + coverage: 1 + + # Composer 1.x + - php-version: 7.4 + composer-version: 1 + - php-version: 7.3 + composer-version: 1 + - php-version: 7.2 + composer-version: 1 + - php-version: 7.1 + composer-version: 1 + + steps: + - uses: actions/checkout@v2 + + # Prepare environment + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-version }} + tools: composer:v${{ matrix.composer-version }} + coverage: xdebug + + # Define Composer cache + - name: Define Composer cache + uses: actions/cache@v1 + with: + path: ~/.composer/cache + key: tests-php-${{ matrix.php-version }}-composer-${{ matrix.composer-version }} + restore-keys: tests-php-${{ matrix.php-version }}-composer- + + # Install Composer dependencies + - name: Install Composer dependencies + run: composer install --no-progress + + # Run tests + - name: Run tests + run: composer test -- --coverage-text + + # Report coverage + - name: Run SonarCloud scan + uses: sonarsource/sonarcloud-github-action@master + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + if: ${{ matrix.coverage }} diff --git a/.travis.yml b/.travis.yml index bf7af2d..d86eef2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,18 +28,18 @@ before_script: - composer install --no-progress script: -- > - if [[ "$COVERAGE" != "1" ]]; then - echo; - echo "Running unit tests"; - .build/bin/phpunit --colors tests/Unit/ - fi - -- > - if [[ "$COVERAGE" == "1" ]]; then - echo; - echo "Running unit tests"; - .build/bin/phpunit --colors -c tests/Build/UnitTests.xml tests/Unit/ - rm -rf .build/vendor/ .build/bin/ - sonar-scanner -Dproject.settings=.sonar-project.properties - fi + - > + if [[ "$COVERAGE" != "1" ]]; then + echo; + echo "Running unit tests"; + .build/bin/phpunit --colors tests/Unit/ + fi + + - > + if [[ "$COVERAGE" == "1" ]]; then + echo; + echo "Running unit tests"; + .build/bin/phpunit --colors -c tests/Build/UnitTests.xml tests/Unit/ + rm -rf .build/vendor/ .build/bin/ + sonar-scanner -Dproject.settings=sonar-project.properties + fi diff --git a/.sonar-project.properties b/sonar-project.properties similarity index 100% rename from .sonar-project.properties rename to sonar-project.properties From b7b5ab9548d9d60a6ae9c1ad3f37cfd0c6214663 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20H=C3=A4u=C3=9Fler?= Date: Mon, 11 Jan 2021 18:27:51 +0100 Subject: [PATCH 3/7] [TASK] Add Unit test for Bundle class generation --- .github/workflows/tests.yaml | 2 +- .gitignore | 3 + composer.json | 3 +- tests/Build/test-application/composer.json | 15 ++++ .../BundleDescriberClassGeneratorTest.php | 68 ++++++++++++++++- tests/Unit/TestApplicationTrait.php | 76 +++++++++++++++++++ 6 files changed, 163 insertions(+), 4 deletions(-) create mode 100644 tests/Build/test-application/composer.json create mode 100644 tests/Unit/TestApplicationTrait.php diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index cff67c4..e3aba26 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -48,7 +48,7 @@ jobs: # Install Composer dependencies - name: Install Composer dependencies - run: composer install --no-progress + run: composer require --dev composer/composer:"^${{ matrix.composer-version }}" --no-progress # Run tests - name: Run tests diff --git a/.gitignore b/.gitignore index 88c2441..c7c5939 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,11 @@ composer.phar /vendor/ .build/ +.phpunit.result.cache # Commit your application's lock file https://getcomposer.org/doc/01-basic-usage.md#commit-your-composer-lock-file-to-version-control # You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file composer.lock src/BundleDescriber.php +/tests/Build/test-application/vendor/ +/tests/Build/test-application/composer.lock diff --git a/composer.json b/composer.json index 0e37a95..f247c41 100644 --- a/composer.json +++ b/composer.json @@ -26,7 +26,8 @@ }, "require-dev": { "phpunit/phpunit": "^7.5.0 || ^8.0.0 || ^9.0.0", - "composer/composer": "^1.6.3 || ^2.0.0" + "composer/composer": "^1.6.3 || ^2.0.0", + "symfony/filesystem": "~4.4.0 || ~5.2.0" }, "autoload": { "psr-4": { diff --git a/tests/Build/test-application/composer.json b/tests/Build/test-application/composer.json new file mode 100644 index 0000000..b89f837 --- /dev/null +++ b/tests/Build/test-application/composer.json @@ -0,0 +1,15 @@ +{ + "name": "cpsit/auditor-test-application", + "repositories": [ + { + "type": "path", + "url": "%APPLICATION_PATH%", + "options": { + "symlink": false + } + } + ], + "require": { + "cpsit/auditor": "*@dev" + } +} diff --git a/tests/Unit/Generator/BundleDescriberClassGeneratorTest.php b/tests/Unit/Generator/BundleDescriberClassGeneratorTest.php index 9f245f1..9f9c8b9 100644 --- a/tests/Unit/Generator/BundleDescriberClassGeneratorTest.php +++ b/tests/Unit/Generator/BundleDescriberClassGeneratorTest.php @@ -20,9 +20,15 @@ ***************************************************************/ use Composer\Composer; +use Composer\Factory; +use Composer\Installer; +use Composer\IO\BufferIO; use Composer\IO\IOInterface; +use CPSIT\Auditor\BundleDescriber; use CPSIT\Auditor\Generator\BundleDescriberClassGenerator; -use CPSIT\Auditor\Reflection\InstallPath; +use CPSIT\Auditor\Reflection\RootPackageReflection; +use CPSIT\Auditor\SettingsInterface as SI; +use CPSIT\Auditor\Tests\Unit\TestApplicationTrait; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -31,6 +37,8 @@ */ class BundleDescriberClassGeneratorTest extends TestCase { + use TestApplicationTrait; + /** * @var BundleDescriberClassGenerator|MockObject */ @@ -51,7 +59,6 @@ class BundleDescriberClassGeneratorTest extends TestCase */ public function setUp(): void { - parent::setUp(); $this->composer = $this->getMockBuilder(Composer::class) ->disableOriginalConstructor() ->getMock(); @@ -63,6 +70,9 @@ public function setUp(): void ->setMethods(['dummy']) ->setConstructorArgs([$this->composer, $this->io]) ->getMock(); + + $this->cleanUpGeneratedFiles(); + $this->initializeTestApplication(); } /** @@ -85,6 +95,47 @@ public function writeFileWritesMessageForMissingFilePath(): void $this->subject->writeFile(); } + /** + * @test + */ + public function writeFileWritesContentsCorrectlyIntoFile(): void + { + // Install Composer dependencies + $io = new BufferIO(); + $composer = (new Factory())->createComposer($io); + static::assertSame( + 0, + Installer::create($io, $composer) + ->setDevMode(false) + ->setPreferDist(true) + ->setVerbose(true) + ->run(), + sprintf('Unable to install Composer dependencies of test application (%s): %s', $this->testApplicationPath, $io->getOutput()) + ); + + // Create class with given contents + $subject = new BundleDescriberClassGenerator($composer, $io); + $properties = RootPackageReflection::getProperties($composer->getPackage()); + $installedPackages = $composer->getRepositoryManager()->getLocalRepository()->getPackages(); + $subject->writeFile($properties, $installedPackages); + + // Check whether the class was generated successfully + $targetFileName = implode(DIRECTORY_SEPARATOR, [ + $composer->getConfig()->get(SI::KEY_VENDOR_DIR), + SI::PACKAGE_IDENTIFIER, + SI::SOURCE_FOLDER_NAME, + SI::BUNDLE_DESCRIBER_CLASS . '.php', + ]); + self::assertFileExists($targetFileName); + self::assertTrue(class_exists(BundleDescriber::class)); + + // Check whether the class contains all relevant properties + foreach ($properties as $propertyKey => $propertyValue) { + self::assertTrue(BundleDescriber::hasProperty($propertyKey)); + self::assertSame($propertyValue, BundleDescriber::getProperty($propertyKey)); + } + } + /** * @test */ @@ -98,4 +149,17 @@ public function writeFileWritesMessageAfterGeneration(): void $this->subject->writeFile(); } + + protected function cleanUpGeneratedFiles(): void + { + $describerClass = dirname(__DIR__, 3) . '/' . SI::SOURCE_FOLDER_NAME . '/' . SI::BUNDLE_DESCRIBER_CLASS . '.php'; + if (file_exists($describerClass)) { + @unlink($describerClass); + } + } + + protected function tearDown(): void + { + $this->cleanUpTestApplication(); + } } diff --git a/tests/Unit/TestApplicationTrait.php b/tests/Unit/TestApplicationTrait.php new file mode 100644 index 0000000..d10951d --- /dev/null +++ b/tests/Unit/TestApplicationTrait.php @@ -0,0 +1,76 @@ + + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +namespace CPSIT\Auditor\Tests\Unit; + +use Symfony\Component\Filesystem\Filesystem; + +/** + * Trait for usage of test application in Unit tests. + * + * @author Elias Häußler + * @license GPL-2.0-or-later + */ +trait TestApplicationTrait +{ + /** + * @var string + */ + protected static $testApplicationTemplate = __DIR__ . '/../Build/test-application'; + + /** + * @var string + */ + protected $testApplicationPath; + + protected function initializeTestApplication(): void + { + // Clean up previous test application + $this->cleanUpTestApplication(); + + // Create test application + $filesystem = new Filesystem(); + $this->testApplicationPath = $filesystem->tempnam(sys_get_temp_dir(), 'auditor_test_'); + $this->cleanUpTestApplication(); + $filesystem->mkdir($this->testApplicationPath); + + // Create composer.json from template file + $sourceComposerJson = static::$testApplicationTemplate . '/composer.json'; + $targetComposerJson = $this->testApplicationPath . '/composer.json'; + $filesystem->dumpFile( + $targetComposerJson, + str_replace('%APPLICATION_PATH%', realpath(dirname(__DIR__)), file_get_contents($sourceComposerJson)) + ); + + // Switch to test application to make Composer dependency management testable + chdir($this->testApplicationPath); + } + + protected function cleanUpTestApplication(): void + { + $filesystem = new Filesystem(); + if (is_string($this->testApplicationPath) && $filesystem->exists($this->testApplicationPath)) { + $filesystem->remove($this->testApplicationPath); + } + } +} From 6f6a712039402fbaf0a00b5708c5ccfdf46a53f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20H=C3=A4u=C3=9Fler?= Date: Mon, 11 Jan 2021 18:34:23 +0100 Subject: [PATCH 4/7] [!!!][BUGFIX] Use serialize() to handle circular references --- .../BundleDescriberClassGenerator.php | 11 ++++--- src/InstalledPackagesTrait.php | 30 ++++++++++++++--- src/PropertiesTrait.php | 32 +++++++++++++------ 3 files changed, 54 insertions(+), 19 deletions(-) diff --git a/src/Generator/BundleDescriberClassGenerator.php b/src/Generator/BundleDescriberClassGenerator.php index 094540b..9f32503 100644 --- a/src/Generator/BundleDescriberClassGenerator.php +++ b/src/Generator/BundleDescriberClassGenerator.php @@ -47,8 +47,8 @@ class BundleDescriberClassGenerator %s implements DescriberInterface { use PropertiesTrait; - static protected $properties = %s; - static protected $installedPackages = %s; + static protected $properties = '%s'; + static protected $installedPackages = '%s'; private function __construct() { @@ -103,12 +103,13 @@ public function writeFile(array $properties = [], array $installedPackages = []) * @param array $installedPackages * @return string */ - protected function generateSource(array $properties, array $installedPackages): string { + protected function generateSource(array $properties, array $installedPackages): string + { return sprintf( self::$generatedClassTemplate, 'fin' . 'al ' . 'cla' . 'ss ' . SI::BUNDLE_DESCRIBER_CLASS, // note: workaround for regex-based code parsers :-( - var_export($properties, true), - var_export($installedPackages, true) + addcslashes(serialize($properties), "'"), + addcslashes(serialize($installedPackages), "'") ); } diff --git a/src/InstalledPackagesTrait.php b/src/InstalledPackagesTrait.php index 0fdeca3..7ee8c32 100644 --- a/src/InstalledPackagesTrait.php +++ b/src/InstalledPackagesTrait.php @@ -26,6 +26,11 @@ */ trait InstalledPackagesTrait { + /** + * @var array|null + */ + protected static $resolvedPackages; + /** * @return array */ @@ -50,17 +55,19 @@ static public function propertyExists(string $propertyName): bool 1557047757 ); } - - + if (!static::arePackagesResolved()) { + static::resolvePackages(); + } return true; } /** - * Get a representation of a installed package + * Get a representation of an installed package + * * @param string $name * @return Package|null */ - static public function getInstalledPackage(string $name): Package + static public function getInstalledPackage(string $name): ?Package { if (!self::isPackageInstalled($name)) { return null; @@ -83,4 +90,17 @@ static public function isPackageInstalled(string $name): bool self::propertyExists(DescriberInterface::INSTALLED_PACKAGES); return (array_key_exists($name, self::$installedPackages)); } -} \ No newline at end of file + + protected static function arePackagesResolved(): bool + { + return is_array(static::$resolvedPackages); + } + + protected static function resolvePackages(): void + { + if (!property_exists(static::class, DescriberInterface::INSTALLED_PACKAGES)) { + return; + } + static::$resolvedPackages = unserialize(static::${DescriberInterface::INSTALLED_PACKAGES}) ?: []; + } +} diff --git a/src/PropertiesTrait.php b/src/PropertiesTrait.php index 5c00c3f..2d1f283 100644 --- a/src/PropertiesTrait.php +++ b/src/PropertiesTrait.php @@ -21,6 +21,11 @@ trait PropertiesTrait { + /** + * @var array|null + */ + protected static $resolvedProperties; + /** * @param string $key * @return mixed @@ -33,18 +38,27 @@ public static function getProperty(string $key) 1557047730 ); } - return self::$properties[$key]; + return static::$resolvedProperties[$key]; } - /** - * @param string $key - * @return boolean - */ public static function hasProperty(string $key):bool { - return ( - property_exists(self::class, 'properties') - && array_key_exists($key, self::$properties) - ); + if (!static::arePropertiesResolved()) { + static::resolveProperties(); + } + return array_key_exists($key, static::$resolvedProperties ?? []); + } + + protected static function arePropertiesResolved(): bool + { + return is_array(static::$resolvedProperties); + } + + protected static function resolveProperties(): void + { + if (!property_exists(self::class, 'properties')) { + return; + } + static::$resolvedProperties = unserialize(self::$properties, ['allowed_classes' => false]) ?: []; } } From e354ba6301b966b89b47b08d51563d1eb9c0a399 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20H=C3=A4u=C3=9Fler?= Date: Mon, 11 Jan 2021 18:47:58 +0100 Subject: [PATCH 5/7] [BUGFIX] Fix coverage report for SonarCloud in CI --- .github/workflows/tests.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index e3aba26..8c43a09 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -55,6 +55,10 @@ jobs: run: composer test -- --coverage-text # Report coverage + - name: Fix coverage path + working-directory: .build/log/coverage + run: sed -i 's/\/home\/runner\/work\/auditor\/auditor\//\/github\/workspace\//g' clover.xml + if: ${{ matrix.coverage }} - name: Run SonarCloud scan uses: sonarsource/sonarcloud-github-action@master env: From efc01551d10e4935adad7bb1ca8df96ad08e8965 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20H=C3=A4u=C3=9Fler?= Date: Mon, 11 Jan 2021 19:25:12 +0100 Subject: [PATCH 6/7] [TASK] Add support for PHP 7.1+ with Composer 2.0 --- .github/workflows/tests.yaml | 15 ++------------- Readme.md | 4 ++-- composer.json | 2 +- src/Reflection/PackageVersions.php | 8 ++++---- 4 files changed, 9 insertions(+), 20 deletions(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 8c43a09..d0055ee 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -9,24 +9,13 @@ jobs: strategy: fail-fast: false matrix: + php-version: [8.0, 7.4, 7.3, 7.2, 7.1] + composer-version: [2, 1] include: - # Composer 2.x - php-version: 8.0 composer-version: 2 - - php-version: 7.4 - composer-version: 2 coverage: 1 - # Composer 1.x - - php-version: 7.4 - composer-version: 1 - - php-version: 7.3 - composer-version: 1 - - php-version: 7.2 - composer-version: 1 - - php-version: 7.1 - composer-version: 1 - steps: - uses: actions/checkout@v2 diff --git a/Readme.md b/Readme.md index 2b83ad7..f41bf45 100644 --- a/Readme.md +++ b/Readme.md @@ -11,8 +11,8 @@ This is a Composer plugin. It allows to access information about the current (ro | | PHP 8.0 | PHP 7.4 | PHP 7.3 | PHP 7.2 | PHP 7.1 | | ------------ | ------- | ------- | ------- | ------- | ------- | -| Composer 1.x | :x: | 0.5.x | 0.5.x | 0.1.0 - 0.5.x | 0.1.0 - 0.5.x -| Composer 2.x | 0.5.x | 0.5.x | :x: | :x: | :x: | +| Composer 1.x | 0.5.x | 0.5.x | 0.5.x | 0.1.0 - 0.5.x | 0.1.0 - 0.5.x +| Composer 2.x | 0.5.x | 0.5.x | 0.5.x | 0.5.x | 0.5.x | ## Usage diff --git a/composer.json b/composer.json index f247c41..b1ef26d 100644 --- a/composer.json +++ b/composer.json @@ -6,7 +6,7 @@ "require": { "php": "^7.1.0 || ~8.0.0", "composer-plugin-api": "^1.0.0 || ^2.0.0", - "ocramius/package-versions": "^1.3.0 || ^2.0.0" + "composer/package-versions-deprecated": "~1.11.99" }, "authors": [ { diff --git a/src/Reflection/PackageVersions.php b/src/Reflection/PackageVersions.php index 8b02b40..84e50ef 100644 --- a/src/Reflection/PackageVersions.php +++ b/src/Reflection/PackageVersions.php @@ -55,10 +55,10 @@ public static function getAll($versions = []) private static function parsePackageVersions(): array { - if (defined(Versions::class . '::VERSIONS')) { - return Versions::VERSIONS; + if (class_exists(InstalledVersions::class)) { + $packages = InstalledVersions::getInstalledPackages(); + return array_map([Versions::class, 'getVersion'], $packages); } - $packages = InstalledVersions::getInstalledPackages(); - return array_map([Versions::class, 'getVersion'], $packages); + return defined(Versions::class . '::VERSIONS') ? Versions::VERSIONS : []; } } From 38f8e99eaa011296eff5d01d76e91d7da14a6251 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20H=C3=A4u=C3=9Fler?= Date: Mon, 11 Jan 2021 19:53:14 +0100 Subject: [PATCH 7/7] [BUGFIX] Apply fixes for linting issues --- src/Dto/NullPackage.php | 3 +++ src/InstalledPackagesTrait.php | 6 +----- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Dto/NullPackage.php b/src/Dto/NullPackage.php index 5c488cf..a6c073e 100644 --- a/src/Dto/NullPackage.php +++ b/src/Dto/NullPackage.php @@ -42,6 +42,7 @@ public function getName(): string */ public function setName(string $name): Package { + // We ignore $name here since the package name is static return $this; } @@ -59,6 +60,7 @@ public function getVersion(): string */ public function setVersion(string $version): Package { + // We ignore $version here since the package version is static return $this; } @@ -76,6 +78,7 @@ public function getSourceReference(): string */ public function setSourceReference(string $sourceReference): Package { + // We ignore $sourceReference here since the packages' source reference is static return $this; } } \ No newline at end of file diff --git a/src/InstalledPackagesTrait.php b/src/InstalledPackagesTrait.php index 7ee8c32..e547685 100644 --- a/src/InstalledPackagesTrait.php +++ b/src/InstalledPackagesTrait.php @@ -72,11 +72,7 @@ static public function getInstalledPackage(string $name): ?Package if (!self::isPackageInstalled($name)) { return null; } - - $package = new Package(self::$installedPackages[$name]); - - return $package; - + return new Package(self::$installedPackages[$name]); } /**