Skip to content
Snippets Groups Projects
Commit 6d50846a authored by Kunal Sachdev's avatar Kunal Sachdev Committed by Adam G-H
Browse files

Issue #3354914 by kunal.sachdev, phenaproxima, Wim Leers, tedbow: Package...

Issue #3354914 by kunal.sachdev, phenaproxima, Wim Leers, tedbow: Package Manager should have status report entry to inform user of Composer version being used
parent c83c648d
No related branches found
No related tags found
2 merge requests!989Issue #3356804 by phenaproxima: Flag a warning during status check if the...,!919Issue #3354914: Package Manager should have status report entry to inform user of Composer version being used
...@@ -7,7 +7,9 @@ ...@@ -7,7 +7,9 @@
declare(strict_types = 1); declare(strict_types = 1);
use Drupal\package_manager\ComposerInspector;
use Drupal\package_manager\Exception\StageFailureMarkerException; use Drupal\package_manager\Exception\StageFailureMarkerException;
use PhpTuf\ComposerStager\Infrastructure\Service\Finder\ExecutableFinderInterface;
/** /**
* Implements hook_requirements(). * Implements hook_requirements().
...@@ -39,6 +41,34 @@ function package_manager_requirements(string $phase) { ...@@ -39,6 +41,34 @@ function package_manager_requirements(string $phase) {
]; ];
} }
} }
if ($phase !== 'runtime') {
return $requirements;
}
/** @var \PhpTuf\ComposerStager\Infrastructure\Service\Finder\ExecutableFinderInterface $executable_finder */
$executable_finder = \Drupal::service(ExecutableFinderInterface::class);
// Report the Composer version in use, as well as its path.
$title = t('Composer version');
try {
$requirements['package_manager_composer'] = [
'title' => $title,
'description' => t('@version (<code>@path</code>)', [
'@version' => \Drupal::service(ComposerInspector::class)->getVersion(),
'@path' => $executable_finder->find('composer'),
]),
'severity' => REQUIREMENT_INFO,
];
}
catch (\Throwable $e) {
$requirements['package_manager_composer'] = [
'title' => $title,
'description' => t('Composer was not found. The error message was: @message', [
'@message' => $e->getMessage(),
]),
'severity' => REQUIREMENT_ERROR,
];
}
return $requirements; return $requirements;
} }
......
...@@ -279,7 +279,7 @@ class ComposerInspector implements LoggerAwareInterface { ...@@ -279,7 +279,7 @@ class ComposerInspector implements LoggerAwareInterface {
* @throws \UnexpectedValueException * @throws \UnexpectedValueException
* Thrown if the Composer version cannot be determined. * Thrown if the Composer version cannot be determined.
*/ */
private function getVersion(): string { public function getVersion(): string {
$this->runner->run(['--format=json'], $this->processCallback->reset()); $this->runner->run(['--format=json'], $this->processCallback->reset());
$data = $this->processCallback->parseJsonOutput(); $data = $this->processCallback->parseJsonOutput();
if (isset($data['application']['name']) if (isset($data['application']['name'])
......
<?php
declare(strict_types = 1);
namespace Drupal\Tests\package_manager\Functional;
use Drupal\package_manager\ComposerInspector;
use Drupal\Tests\BrowserTestBase;
use PhpTuf\ComposerStager\Infrastructure\Service\Finder\ExecutableFinderInterface;
/**
* Tests that Package Manager shows the Composer version on the status report.
*
* @group package_manager
* @internal
*/
class ComposerRequirementTest extends BrowserTestBase {
/**
* {@inheritdoc}
*/
protected static $modules = ['package_manager'];
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'stark';
/**
* Tests that Composer and file syncer info is listed on the status report.
*/
public function testComposerInfoShown(): void {
/** @var \PhpTuf\ComposerStager\Infrastructure\Service\Finder\ExecutableFinderInterface $executable_finder */
$executable_finder = $this->container->get(ExecutableFinderInterface::class);
$composer_path = $executable_finder->find('composer');
$composer_version = $this->container->get(ComposerInspector::class)->getVersion();
$account = $this->drupalCreateUser(['administer site configuration']);
$this->drupalLogin($account);
$this->drupalGet('/admin/reports/status');
$assert_session = $this->assertSession();
$assert_session->pageTextContains('Composer version');
$assert_session->responseContains("$composer_version (<code>$composer_path</code>)");
// If the path to Composer is invalid, we should see the error message
// that gets raised when we try to get its version.
$this->config('package_manager.settings')
->set('executables.composer', '/path/to/composer')
->save();
$this->getSession()->reload();
$assert_session->statusCodeEquals(200);
$assert_session->pageTextContains('Composer was not found. The error message was: The command "\'/path/to/composer\' \'--format=json\'" failed.');
}
}
...@@ -20,6 +20,7 @@ use PhpTuf\ComposerStager\Domain\Service\Precondition\ComposerIsAvailableInterfa ...@@ -20,6 +20,7 @@ use PhpTuf\ComposerStager\Domain\Service\Precondition\ComposerIsAvailableInterfa
use PhpTuf\ComposerStager\Domain\Service\ProcessRunner\ComposerRunnerInterface; use PhpTuf\ComposerStager\Domain\Service\ProcessRunner\ComposerRunnerInterface;
use PhpTuf\ComposerStager\Infrastructure\Factory\Path\PathFactory; use PhpTuf\ComposerStager\Infrastructure\Factory\Path\PathFactory;
use Prophecy\Argument; use Prophecy\Argument;
use Prophecy\Prophecy\ObjectProphecy;
/** /**
* @coversDefaultClass \Drupal\package_manager\ComposerInspector * @coversDefaultClass \Drupal\package_manager\ComposerInspector
...@@ -240,29 +241,12 @@ class ComposerInspectorTest extends PackageManagerKernelTestBase { ...@@ -240,29 +241,12 @@ class ComposerInspectorTest extends PackageManagerKernelTestBase {
* [null, "Unable to determine Composer version"] * [null, "Unable to determine Composer version"]
*/ */
public function testVersionCheck(?string $reported_version, ?string $expected_message): void { public function testVersionCheck(?string $reported_version, ?string $expected_message): void {
$runner = $this->prophesize(ComposerRunnerInterface::class); $runner = $this->mockComposerRunner($reported_version);
$pass_version_to_output_callback = function (array $arguments_passed_to_runner) use ($reported_version): void {
$command_output = Json::encode([
'application' => [
'name' => 'Composer',
'version' => $reported_version,
],
]);
/** @var \Drupal\package_manager\ProcessOutputCallback $callback */
[, $callback] = $arguments_passed_to_runner;
$callback($callback::OUT, $command_output);
};
// We expect the runner to be called with two arguments: an array whose // The result of the version check is statically cached, so the runner
// first item is `--format=json`, and an output callback. The result of the // should only be called once, even though we call validate() twice in this
// version check is statically cached, so the runner should only be called // test.
// once, even though we call validate() twice in this test. $runner->getMethodProphecies('run')[0]->shouldBeCalledOnce();
$runner->run(
Argument::withEntry(0, '--format=json'),
Argument::type(ProcessOutputCallback::class)
)->will($pass_version_to_output_callback)->shouldBeCalledOnce();
// The runner should be called with `validate` as the first argument, but // The runner should be called with `validate` as the first argument, but
// it won't affect the outcome of this test. // it won't affect the outcome of this test.
$runner->run(Argument::withEntry(0, 'validate')); $runner->run(Argument::withEntry(0, 'validate'));
...@@ -294,6 +278,22 @@ class ComposerInspectorTest extends PackageManagerKernelTestBase { ...@@ -294,6 +278,22 @@ class ComposerInspectorTest extends PackageManagerKernelTestBase {
$inspector->validate($project_root); $inspector->validate($project_root);
} }
/**
* @covers ::getVersion
*
* @testWith ["2.5.6"]
* [null]
*/
public function testGetVersion(?string $reported_version): void {
$this->container->set(ComposerRunnerInterface::class, $this->mockComposerRunner($reported_version)->reveal());
if (empty($reported_version)) {
$this->expectException(\UnexpectedValueException::class);
$this->expectExceptionMessage('Unable to determine Composer version');
}
$this->assertSame($reported_version, $this->container->get(ComposerInspector::class)->getVersion());
}
/** /**
* @covers ::validate * @covers ::validate
*/ */
...@@ -474,4 +474,39 @@ class ComposerInspectorTest extends PackageManagerKernelTestBase { ...@@ -474,4 +474,39 @@ class ComposerInspectorTest extends PackageManagerKernelTestBase {
$this->assertSame($expected_value, $actual_value); $this->assertSame($expected_value, $actual_value);
} }
/**
* Mocks the Composer runner service to return a particular version string.
*
* @param string|null $reported_version
* The version number that `composer --format=json` should return.
*
* @return \Prophecy\Prophecy\ObjectProphecy
* The configurator for the mocked Composer runner.
*/
private function mockComposerRunner(?string $reported_version): ObjectProphecy {
$runner = $this->prophesize(ComposerRunnerInterface::class);
$pass_version_to_output_callback = function (array $arguments_passed_to_runner) use ($reported_version): void {
$command_output = Json::encode([
'application' => [
'name' => 'Composer',
'version' => $reported_version,
],
]);
/** @var \Drupal\package_manager\ProcessOutputCallback $callback */
[, $callback] = $arguments_passed_to_runner;
$callback($callback::OUT, $command_output);
};
// We expect the runner to be called with two arguments: an array whose
// first item is `--format=json`, and an output callback.
$runner->run(
Argument::withEntry(0, '--format=json'),
Argument::type(ProcessOutputCallback::class)
)->will($pass_version_to_output_callback);
return $runner;
}
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment