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
No related merge requests found
......@@ -7,7 +7,9 @@
declare(strict_types = 1);
use Drupal\package_manager\ComposerInspector;
use Drupal\package_manager\Exception\StageFailureMarkerException;
use PhpTuf\ComposerStager\Infrastructure\Service\Finder\ExecutableFinderInterface;
/**
* Implements hook_requirements().
......@@ -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;
}
......
......@@ -279,7 +279,7 @@ class ComposerInspector implements LoggerAwareInterface {
* @throws \UnexpectedValueException
* Thrown if the Composer version cannot be determined.
*/
private function getVersion(): string {
public function getVersion(): string {
$this->runner->run(['--format=json'], $this->processCallback->reset());
$data = $this->processCallback->parseJsonOutput();
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
use PhpTuf\ComposerStager\Domain\Service\ProcessRunner\ComposerRunnerInterface;
use PhpTuf\ComposerStager\Infrastructure\Factory\Path\PathFactory;
use Prophecy\Argument;
use Prophecy\Prophecy\ObjectProphecy;
/**
* @coversDefaultClass \Drupal\package_manager\ComposerInspector
......@@ -240,29 +241,12 @@ class ComposerInspectorTest extends PackageManagerKernelTestBase {
* [null, "Unable to determine Composer version"]
*/
public function testVersionCheck(?string $reported_version, ?string $expected_message): void {
$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);
};
$runner = $this->mockComposerRunner($reported_version);
// We expect the runner to be called with two arguments: an array whose
// first item is `--format=json`, and an output callback. The result of the
// version check is statically cached, so the runner should only be called
// once, even though we call validate() twice in this test.
$runner->run(
Argument::withEntry(0, '--format=json'),
Argument::type(ProcessOutputCallback::class)
)->will($pass_version_to_output_callback)->shouldBeCalledOnce();
// The result of the version check is statically cached, so the runner
// should only be called once, even though we call validate() twice in this
// test.
$runner->getMethodProphecies('run')[0]->shouldBeCalledOnce();
// The runner should be called with `validate` as the first argument, but
// it won't affect the outcome of this test.
$runner->run(Argument::withEntry(0, 'validate'));
......@@ -294,6 +278,22 @@ class ComposerInspectorTest extends PackageManagerKernelTestBase {
$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
*/
......@@ -474,4 +474,39 @@ class ComposerInspectorTest extends PackageManagerKernelTestBase {
$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