Skip to content

Commit

Permalink
Merge pull request #112 from Jean85/backport-82
Browse files Browse the repository at this point in the history
Backport #82 to 1.4
  • Loading branch information
Ocramius committed Nov 14, 2019
2 parents a4d4b60 + 10ad401 commit 7ca61c2
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 44 deletions.
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"composer-plugin-api": "^1.0.0"
},
"require-dev": {
"phpunit/phpunit": "^7.0.0",
"phpunit/phpunit": "^7.5.17",
"infection/infection": "^0.7.1",
"composer/composer": "^1.6.3",
"ext-zip": "*",
Expand Down
67 changes: 49 additions & 18 deletions src/PackageVersions/FallbackVersions.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@
use UnexpectedValueException;
use function array_key_exists;
use function array_merge;
use function basename;
use function file_exists;
use function file_get_contents;
use function getcwd;
use function iterator_to_array;
use function json_decode;
use function json_encode;
Expand Down Expand Up @@ -38,51 +40,80 @@ private function __construct()
*/
public static function getVersion(string $packageName) : string
{
$versions = iterator_to_array(self::getVersions(self::getComposerLockPath()));
$versions = iterator_to_array(self::getVersions(self::getPackageData()));

if (! array_key_exists($packageName, $versions)) {
throw new OutOfBoundsException(
'Required package "' . $packageName . '" is not installed: cannot detect its version'
'Required package "' . $packageName . '" is not installed: check your ./vendor/composer/installed.json and/or ./composer.lock files'
);
}

return $versions[$packageName];
}

/**
* @return mixed[]
*
* @throws UnexpectedValueException
*/
private static function getComposerLockPath() : string
private static function getPackageData() : array
{
// bold assumption, but there's not here to fix everyone's problems.
$checkedPaths = [__DIR__ . '/../../../../../composer.lock', __DIR__ . '/../../composer.lock'];
$checkedPaths = [
// The top-level project's ./vendor/composer/installed.json
getcwd() . '/vendor/composer/installed.json',
// The top-level project's ./composer.lock
getcwd() . '/composer.lock',
// This package's composer.lock
__DIR__ . '/../../composer.lock',
];

$packageData = [];
foreach ($checkedPaths as $path) {
if (file_exists($path)) {
return $path;
if (! file_exists($path)) {
continue;
}

$data = json_decode(file_get_contents($path), true);
switch (basename($path)) {
case 'installed.json':
$packageData[] = $data;
break;
case 'composer.lock':
$packageData[] = $data['packages'] + ($data['packages-dev'] ?? []);
break;
default:
// intentionally left blank
}
}

if ($packageData !== []) {
return array_merge(...$packageData);
}

throw new UnexpectedValueException(sprintf(
'PackageVersions could not locate your `composer.lock` location. This is assumed to be in %s. '
. 'If you customized your composer vendor directory and ran composer installation with --no-scripts, '
. 'then you are on your own, and we can\'t really help you. Fix your shit and cut the tooling some slack.',
'PackageVersions could not locate the `vendor/composer/installed.json` or your `composer.lock` '
. 'location. This is assumed to be in %s. If you customized your composer vendor directory and ran composer '
. 'installation with --no-scripts or if you deployed without the required composer files, then you are on '
. 'your own, and we can\'t really help you. Fix your shit and cut the tooling some slack.',
json_encode($checkedPaths)
));
}

private static function getVersions(string $composerLockFile) : Generator
/**
* @param mixed[] $packageData
*
* @return Generator&string[]
*
* @psalm-return Generator<string, string>
*/
private static function getVersions(array $packageData) : Generator
{
$lockData = json_decode(file_get_contents($composerLockFile), true);

$lockData['packages-dev'] = $lockData['packages-dev'] ?? [];

foreach (array_merge($lockData['packages'], $lockData['packages-dev']) as $package) {
foreach ($packageData as $package) {
yield $package['name'] => $package['version'] . '@' . (
$package['source']['reference']?? $package['dist']['reference'] ?? ''
$package['source']['reference'] ?? $package['dist']['reference'] ?? ''
);
}

yield self::ROOT_PACKAGE_NAME;
yield self::ROOT_PACKAGE_NAME => self::ROOT_PACKAGE_NAME;
}
}
2 changes: 1 addition & 1 deletion src/PackageVersions/Installer.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public static function getVersion(string $packageName) : string
}
throw new \OutOfBoundsException(
'Required package "' . $packageName . '" is not installed: cannot detect its version'
'Required package "' . $packageName . '" is not installed: check your ./vendor/composer/installed.json and/or ./composer.lock files'
);
}
}
Expand Down
89 changes: 69 additions & 20 deletions test/PackageVersionsTest/FallbackVersionsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
use PHPUnit\Framework\TestCase;
use UnexpectedValueException;
use function array_merge;
use function file_exists;
use function file_get_contents;
use function getcwd;
use function json_decode;
use function json_encode;
use function realpath;
use function rename;
use function uniqid;

Expand All @@ -21,39 +21,68 @@
*/
final class FallbackVersionsTest extends TestCase
{
public function testWillFailWithoutValidComposerLockLocation() : void
public function testWillFailWithoutValidPackageData() : void
{
rename(__DIR__ . '/../../composer.lock', __DIR__ . '/../../composer.lock.backup');
$this->backupFile(__DIR__ . '/../../vendor/composer/installed.json');
$this->backupFile(__DIR__ . '/../../composer.lock');

try {
FallbackVersions::getVersion('phpunit/phpunit');
$this->expectException(UnexpectedValueException::class);
$this->expectExceptionMessageRegExp(
'@PackageVersions could not locate the `vendor/composer/installed\.json` or your `composer\.lock` '
. 'location\. This is assumed to be in \[[^]]+?\]\. If you customized your composer vendor directory and ran composer '
. 'installation with --no-scripts or if you deployed without the required composer files, then you are on '
. 'your own, and we can\'t really help you\. Fix your shit and cut the tooling some slack\.@'
);

self::fail('An exception was supposed to be thrown');
} catch (UnexpectedValueException $lockFileNotFound) {
$srcDir = realpath(__DIR__ . '/../../src/PackageVersions');
FallbackVersions::getVersion('phpunit/phpunit');
}

public function testValidVersions() : void
{
$lockData = json_decode(file_get_contents(__DIR__ . '/../../composer.lock'), true);

$packages = array_merge($lockData['packages'], $lockData['packages-dev']);

self::assertNotEmpty($packages);

foreach ($packages as $package) {
self::assertSame(
'PackageVersions could not locate your `composer.lock` location. '
. 'This is assumed to be in '
. json_encode([$srcDir . '/../../../../../composer.lock', $srcDir . '/../../composer.lock'])
. '. If you customized your composer vendor directory and ran composer installation with --no-scripts, '
. 'then you are on your own, and we can\'t really help you. '
. 'Fix your shit and cut the tooling some slack.',
$lockFileNotFound->getMessage()
$package['version'] . '@' . $package['source']['reference'],
FallbackVersions::getVersion($package['name'])
);
} finally {
rename(__DIR__ . '/../../composer.lock.backup', __DIR__ . '/../../composer.lock');
}
}

public function testValidVersions() : void
public function testValidVersionsWithoutComposerLock() : void
{
$lockData = json_decode(file_get_contents(__DIR__ . '/../../composer.lock'), true);

$packages = array_merge($lockData['packages'], $lockData['packages-dev']);
$packages = array_merge($lockData['packages'], $lockData['packages-dev'] ?? []);

self::assertNotEmpty($packages);

$this->backupFile(__DIR__ . '/../../composer.lock');
foreach ($packages as $package) {
self::assertSame(
$package['version'] . '@' . $package['source']['reference'],
FallbackVersions::getVersion($package['name'])
);
}
}

public function testValidVersionsWithoutInstalledJson() : void
{
$packages = json_decode(file_get_contents(__DIR__ . '/../../vendor/composer/installed.json'), true);

if ($packages === []) {
// In case of --no-dev flag
$lockData = json_decode(file_get_contents(getcwd() . '/composer.lock'), true);
$packages = array_merge($lockData['packages'], $lockData['packages-dev'] ?? []);
}

self::assertNotEmpty($packages);

$this->backupFile(__DIR__ . '/../../vendor/composer/installed.json');
foreach ($packages as $package) {
self::assertSame(
$package['version'] . '@' . $package['source']['reference'],
Expand All @@ -68,4 +97,24 @@ public function testInvalidVersionsAreRejected() : void

FallbackVersions::getVersion(uniqid('', true) . '/' . uniqid('', true));
}

protected function tearDown() : void
{
$this->revertFile(__DIR__ . '/../../composer.lock');
$this->revertFile(__DIR__ . '/../../vendor/composer/installed.json');
}

private function backupFile(string $filename) : void
{
rename($filename, $filename . '.backup');
}

private function revertFile(string $filename) : void
{
if (! file_exists($filename . '.backup')) {
return;
}

rename($filename . '.backup', $filename);
}
}
8 changes: 4 additions & 4 deletions test/PackageVersionsTest/InstallerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ public static function getVersion(string $packageName) : string
}
throw new \OutOfBoundsException(
'Required package "' . $packageName . '" is not installed: cannot detect its version'
'Required package "' . $packageName . '" is not installed: check your ./vendor/composer/installed.json and/or ./composer.lock files'
);
}
}
Expand Down Expand Up @@ -348,7 +348,7 @@ public static function getVersion(string $packageName) : string
}
throw new \OutOfBoundsException(
'Required package "' . $packageName . '" is not installed: cannot detect its version'
'Required package "' . $packageName . '" is not installed: check your ./vendor/composer/installed.json and/or ./composer.lock files'
);
}
}
Expand Down Expand Up @@ -455,7 +455,7 @@ public static function getVersion(string $packageName) : string
}
throw new \OutOfBoundsException(
'Required package "' . $packageName . '" is not installed: cannot detect its version'
'Required package "' . $packageName . '" is not installed: check your ./vendor/composer/installed.json and/or ./composer.lock files'
);
}
}
Expand Down Expand Up @@ -854,7 +854,7 @@ public static function getVersion(string $packageName) : string
}
throw new \OutOfBoundsException(
'Required package "' . $packageName . '" is not installed: cannot detect its version'
'Required package "' . $packageName . '" is not installed: check your ./vendor/composer/installed.json and/or ./composer.lock files'
);
}
}
Expand Down

0 comments on commit 7ca61c2

Please sign in to comment.