Skip to content

Commit

Permalink
allow setting php version from config or composer.json
Browse files Browse the repository at this point in the history
if a composer.json is present and a PHP version requirement is
configured, we set the php version to the minimal PHP version that
satisfies the composer requirement.

Additionally, this adds a `phpVersion` attribute to the <psalm> tag. If
that's set, it takes precedence over what has been detected in
composer.json.

And finally, the --php-version command line flag continues to work and
takes precedence over the setting in the <psalm> tag

this fixes #2628
  • Loading branch information
pilif authored and muglug committed Jan 30, 2020
1 parent 39a4828 commit f6983fd
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 1 deletion.
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,14 @@
],
"require": {
"php": "^7.1.3|^8",
"ext-SimpleXML": "*",
"ext-dom": "*",
"ext-json": "*",
"ext-libxml": "*",
"ext-SimpleXML": "*",
"ext-tokenizer": "*",
"amphp/amp": "^2.1",
"amphp/byte-stream": "^1.5",
"composer/semver": "^1.5",
"composer/xdebug-handler": "^1.1",
"felixfbecker/advanced-json-rpc": "^3.0.3",
"felixfbecker/language-server-protocol": "^1.4",
Expand Down
1 change: 1 addition & 0 deletions config.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
<xs:attribute name="errorBaseline" type="xs:string" />
<xs:attribute name="maxStringLength" type="xs:string" />
<xs:attribute name="name" type="xs:string" />
<xs:attribute name="phpVersion" type="xs:string" />
<xs:attribute name="serializer" type="xs:string" />

<xs:attribute name="addParamDefaultToDocblockType" type="xs:boolean" default="false" />
Expand Down
46 changes: 46 additions & 0 deletions src/Psalm/Config.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?php
namespace Psalm;

use Composer\Semver\Semver;
use Webmozart\PathUtil\Path;
use function array_merge;
use function array_pop;
Expand Down Expand Up @@ -182,6 +183,13 @@ class Config
*/
public $base_dir;

/**
* The PHP version to assume as declared in the config file
*
* @var string|null
*/
private $configured_php_version;

/**
* @var array<int, string>
*/
Expand Down Expand Up @@ -745,6 +753,10 @@ private static function fromXmlAndPaths(string $base_dir, string $file_contents,
$base_dir = $current_dir;
}

if (isset($config_xml['phpVersion'])) {
$config->configured_php_version = (string) $config_xml['phpVersion'];
}

if (isset($config_xml['autoloader'])) {
$autoloader_path = $config->base_dir . DIRECTORY_SEPARATOR . $config_xml['autoloader'];

Expand Down Expand Up @@ -1861,8 +1873,42 @@ public function addStubFile(string $stub_file)
$this->stub_files[] = $stub_file;
}

public function getPhpVersion(): ?string
{
if (isset($this->configured_php_version)) {
return $this->configured_php_version;
}

return $this->getPHPVersionFromComposerJson();
}

private function setBooleanAttribute(string $name, bool $value): void
{
$this->$name = $value;
}

/**
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedArrayAccess
*/
private function getPHPVersionFromComposerJson(): ?string
{
$composer_json_path = $this->base_dir . DIRECTORY_SEPARATOR. 'composer.json';

if (file_exists($composer_json_path)) {
if (!$composer_json = json_decode(file_get_contents($composer_json_path), true)) {
throw new \UnexpectedValueException('Invalid composer.json at ' . $composer_json_path);
}
$php_version = $composer_json['require']['php'] ?? null;

if ($php_version) {
foreach (['5.4', '5.5', '5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0'] as $candidate) {
if (Semver::satisfies($candidate, (string)$php_version)) {
return $candidate;
}
}
}
}
return null;
}
}
4 changes: 4 additions & 0 deletions src/psalm.php
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,10 @@ function ($arg) {
$progress
);

if (!isset($options['php-version'])) {
$options['php-version'] = $config->getPhpVersion();
}

if (isset($options['php-version'])) {
if (!is_string($options['php-version'])) {
die('Expecting a version number in the format x.y' . PHP_EOL);
Expand Down
26 changes: 26 additions & 0 deletions tests/Config/ConfigTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1451,4 +1451,30 @@ public function testGetPossiblePsr4Path()
$config->getPotentialComposerFilePathForClassLike('Psalm\\Tests\\Foo')
);
}

/**
* @return void
*/
public function testTakesPhpVersionFromConfigFile()
{
$cfg = Config::loadFromXML(
dirname(__DIR__, 2),
'<?xml version="1.0"?><psalm phpVersion="7.1"></psalm>'
);
$this->assertSame('7.1', $cfg->getPhpVersion());
}

/**
* @return void
*/
public function testReadsComposerJsonForPhpVersion()
{

$root = __DIR__ . '/../fixtures/ComposerPhpVersion';
$cfg = Config::loadFromXML($root, "<?xml version=\"1.0\"?><psalm></psalm>");
$this->assertSame('7.2', $cfg->getPhpVersion());

$cfg = Config::loadFromXML($root, "<?xml version=\"1.0\"?><psalm phpVersion='8.0'></psalm>");
$this->assertSame('8.0', $cfg->getPhpVersion());
}
}
5 changes: 5 additions & 0 deletions tests/fixtures/ComposerPhpVersion/composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"require": {
"php": "7.2|7.3,<8"
}
}

0 comments on commit f6983fd

Please sign in to comment.