8000 Add options to automatically run suggested command if there is only 1… · symfony/symfony@3524d9d · GitHub
[go: up one dir, main page]

Skip to content

Commit 3524d9d

Browse files
committed
Add options to automatically run suggested command if there is only 1 alternative
1 parent a97f8b7 commit 3524d9d

12 files changed

+156
-26
lines changed

UPGRADE-4.1.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,27 @@
11
UPGRADE FROM 4.0 to 4.1
22
=======================
33

4+
Console
5+
-------
6+
7+
* The `Application::findNamespace` method throws an instance of `NamespaceNotFoundException` instead `CommandNotFoundException`. All catch statements should be updated to cater for both exceptions, E.G
8+
9+
Before:
10+
```php
11+
try {
12+
$app->run();
13+
} catch (CommandNotFoundException $e) {
14+
}
15+
```
16+
17+
After:
18+
```php
19+
try {
20+
$app->run();
21+
} catch (NamespaceNotFoundException | CommandNotFoundException $e) {
22+
}
23+
```
24+
425
HttpFoundation
526
--------------
627

UPGRADE-5.0.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,27 @@
11
UPGRADE FROM 4.x to 5.0
22
=======================
33

4+
Console
5+
-------
6+
7+
* The `NamespaceNotFoundException` doesn't extend `CommandNotFoundException` anymore. All catch statements should be updated to cater for both exceptions, E.G
8+
9+
Before:
10+
```php
11+
try {
12+
$app->run();
13+
} catch (CommandNotFoundException $e) {
14+
}
15+
```
16+
17+
After:
18+
```php
19+
try {
20+
$app->run();
21+
} catch (NamespaceNotFoundException | CommandNotFoundException $e) {
22+
}
23+
```
24+
425
HttpFoundation
526
--------------
627

src/Symfony/Component/Console/Application.php

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use Symfony\Component\Console\CommandLoader\CommandLoaderInterface;
1515
use Symfony\Component\Console\Exception\ExceptionInterface;
16+
use Symfony\Component\Console\Exception\NamespaceNotFoundException;
1617
use Symfony\Component\Console\Formatter\OutputFormatter;
1718
use Symfony\Component\Console\Helper\DebugFormatterHelper;
1819
use Symfony\Component\Console\Helper\Helper;
@@ -39,6 +40,7 @@
3940
use Symfony\Component\Console\Event\ConsoleTerminateEvent;
4041
use Symfony\Component\Console\Exception\CommandNotFoundException;
4142
use Symfony\Component\Console\Exception\LogicException;
43+
use Symfony\Component\Console\Question\ConfirmationQuestion;
4244
use Symfony\Component\Debug\ErrorHandler;
4345
use Symfony\Component\Debug\Exception\FatalThrowableError;
4446
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
@@ -226,7 +228,19 @@ public function doRun(InputInterface $input, OutputInterface $output)
226228
$e = $event->getError();
227229
}
228230

229-
throw $e;
231+
if (!($e instanceof CommandNotFoundException && !$e instanceof NamespaceNotFoundException) || 1 !== count($alternatives = $e->getAlternatives()) || !$input->isInteractive()) {
232+
throw $e;
233+
}
234+
235+
$alternative = $alternatives[0];
236+
$output->writeln(sprintf('<error>Command "%s" is not defined.</error>', $name));
237+
$question = new ConfirmationQuestion(sprintf('Do you want to run "%s" instead? [y/n] ', $alternative), false);
238+
239+
if (!(new QuestionHelper())->ask($input, $output, $question)) {
240+
return 1;
241+
}
242+
243+
$command = $this->find($alternative);
230244
}
231245

232246
$this->runningCommand = $command;
@@ -525,7 +539,7 @@ public function getNamespaces()
525539
*
526540
* @return string A registered namespace
527541
*
528-
* @throws CommandNotFoundException When namespace is incorrect or ambiguous
542+
* @throws NamespaceNotFoundException When namespace is incorrect or ambiguous
529543
*/
530544
public function findNamespace($namespace)
531545
{
@@ -546,12 +560,12 @@ public function findNamespace($namespace)
546560
$message .= implode("\n ", $alternatives);
547561
}
548562

549-
throw new CommandNotFoundException($message, $alternatives);
563+
throw new NamespaceNotFoundException($message, $alternatives);
550564
}
551565

552566
$exact = in_array($namespace, $namespaces, true);
553567
if (count($namespaces) > 1 && !$exact) {
554-
throw new CommandNotFoundException(sprintf("The namespace \"%s\" is ambiguous.\nDid you mean one of these?\n%s", $namespace, $this->getAbbreviationSuggestions(array_values($namespaces))), array_values($namespaces));
568+
throw new NamespaceNotFoundException(sprintf("The namespace \"%s\" is ambiguous.\nDid you mean one of these?\n%s", $namespace, $this->getAbbreviationSuggestions(array_values($namespaces))), array_values($namespaces));
555569
}
556570

557571
return $exact ? $namespace : reset($namespaces);

src/Symfony/Component/Console/CHANGELOG.md

Lines changed: 7 additions & 2 deletions
Original file line number
Diff line numberDiff line change
@@ -1,15 +1,20 @@
11
CHANGELOG
22
=========
33

4+
4.1.0
5+
-----
6+
7+
* added option to run suggested command if command is not found and only 1 alternative is available
8+
49
4.0.0
510
-----
611

712
* `OutputFormatter` throws an exception when unknown options are used
813
* removed `QuestionHelper::setInputStream()/getInputStream()`
914
* removed `Application::getTerminalWidth()/getTerminalHeight()` and
1015
`Application::setTerminalDimensions()/getTerminalDimensions()`
11-
* removed `ConsoleExceptionEvent`
12-
* removed `ConsoleEvents::EXCEPTION`
16+
* removed `ConsoleExceptionEvent`
17+
* removed `ConsoleEvents::EXCEPTION`
1318

1419
3.4.0
1520
-----
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Console\Exception;
13+
14+
/**
15+
* Represents an incorrect namespace typed in the console.
16+
*
17+
* @author Pierre du Plessis <pdples@gmail.com>
18+
*
19+
* @deprecated This class won't extend CommandNotFoundException in Symfony 5
20+
*/
21+
class NamespaceNotFoundException extends CommandNotFoundException
22+
{
23+
}

src/Symfony/Component/Console/Tests/ApplicationTest.php

Lines changed: 40 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use Symfony\Component\Console\Command\Command;
1717
use Symfony\Component\Console\CommandLoader\FactoryCommandLoader;
1818
use Symfony\Component\Console\DependencyInjection\AddConsoleCommandPass;
19+
use Symfony\Component\Console\Exception\NamespaceNotFoundException;
1920
use Symfony\Component\Console\Helper\HelperSet;
2021
use Symfony\Component\Console\Helper\FormatterHelper;
2122
use Symfony\Component\Console\Input\ArgvInput;
@@ -56,6 +57,7 @@ public static function setUpBeforeClass()
5657
require_once self::$fixturesPath.'/BarBucCommand.php';
5758
require_once self::$fixturesPath.'/FooSubnamespaced1Command.php';
5859
require_once self::$fixturesPath.'/FooSubnamespaced2Command.php';
60+
require_once self::$fixturesPath.'/FooWithoutAliasCommand.php';
5961
require_once self::$fixturesPath.'/TestTiti.php';
6062
require_once self::$fixturesPath.'/TestToto.php';
6163
}
@@ -275,10 +277,10 @@ public function testFindAmbiguousNamespace()
275277
$expectedMsg = "The namespace \"f\" is ambiguous.\nDid you mean one of these?\n foo\n foo1";
276278

277279
if (method_exists($this, 'expectException')) {
278-
$this->expectException(CommandNotFoundException::class);
280+
$this->expectException(NamespaceNotFoundException::class);
279281
$this->expectExceptionMessage($expectedMsg);
280282
} else {
281-
$this->setExpectedException(CommandNotFoundException::class, $expectedMsg);
283+
$this->setExpectedException(NamespaceNotFoundException::class, $expectedMsg);
282284
}
283285

284286
$application->findNamespace('f');
@@ -293,7 +295,7 @@ public function testFindNonAmbiguous()
293295
}
294296

295297
/**
296-
* @expectedException \Symfony\Component\Console\Exception\CommandNotFoundException
298+
* @expectedException \Symfony\Component\Console\Exception\NamespaceNotFoundException
297299
* @expectedExceptionMessage There are no commands defined in the "bar" namespace.
298300
*/
299301
public function testFindInvalidNamespace()
@@ -457,6 +459,29 @@ public function testFindAlternativeExceptionMessageSingle($name)
457459
$application->find($name);
458460
}
459461

462+
public function testCanRunAlternativeCommandName()
463+
{
464+
$application = new Application();
465+
$application->add(new \FooWithoutAliasCommand());
466+
$application->setAutoExit(false);
467+
$tester = new ApplicationTester($application);
468+
$tester->setInputs(array('y'));
469+
$tester->run(array('command' => 'foos'), array('decorated' => false));
470+
$this->assertSame("Command \"foos\" is not defined.\nDo you want to run \"foo\" instead? [y/n] called\n", $tester->getDisplay(true));
471+
}
472+
473+
public function testDontRunAlternativeCommandName()
474+
{
475+
$application = new Application();
476+
$application->add(new \FooWithoutAliasCommand());
477+
$application->setAutoExit(false);
478+
$tester = new ApplicationTester($application);
479+
$tester->setInputs(array('n'));
480+
$exitCode = $tester->run(array('command' => 'foos'), array('decorated' => false));
481+
$this->assertSame(1, $exitCode);
482+
$this->assertSame("Command \"foos\" is not defined.\nDo you want to run \"foo\" instead? [y/n] ", $tester->getDisplay(true));
483+
}
484+
460485
public function provideInvalidCommandNamesSingle()
461486
{
462487
return array(
@@ -486,10 +511,10 @@ public function testFindAlternativeExceptionMessageMultiple()
486511
// Namespace + plural
487512
try {
488513
$application->find('foo2:bar');
489-
$this->fail('->find() throws a CommandNotFoundException if command does not exist, with alternatives');
514+
$this->fail('->find() throws a NamespaceNotFoundException if command does not exist, with alternatives');
490515
} catch (\Exception $e) {
491-
$this->assertInstanceOf('Symfony\Component\Console\Exception\CommandNotFoundException', $e, '->find() throws a CommandNotFoundException if command does not exist, with alternatives');
492-
$this->assertRegExp('/Did you mean one of these/', $e->getMessage(), '->find() throws a CommandNotFoundException if command does not exist, with alternatives');
516+
$this->assertInstanceOf('Symfony\Component\Console\Exception\NamespaceNotFoundException', $e, '->find() throws a NamespaceNotFoundException if command does not exist, with alternatives');
517+
$this->assertRegExp('/Did you mean one of these/', $e->getMessage(), '->find() throws a NamespaceNotFoundException if command does not exist, with alternatives');
493518
$this->assertRegExp('/foo1/', $e->getMessage());
494519
}
495520

@@ -563,26 +588,26 @@ public function testFindAlternativeNamespace()
563588

564589
try {
565590
$application->find('Unknown-namespace:Unknown-command');
566-
$this->fail('->find() throws a CommandNotFoundException if namespace does not exist');
591+
$this->fail('->find() throws a NamespaceNotFoundException if namespace does not exist');
567592
} catch (\Exception $e) {
568-
$this->assertInstanceOf('Symfony\Component\Console\Exception\CommandNotFoundException', $e, '->find() throws a CommandNotFoundException if namespace does not exist');
593+
$this->assertInstanceOf('Symfony\Component\Console\Exception\NamespaceNotFoundException', $e, '->find() throws a NamespaceNotFoundException if namespace does not exist');
569594
$this->assertSame(array(), $e->getAlternatives());
570-
$this->assertEquals('There are no commands defined in the "Unknown-namespace" namespace.', $e->getMessage(), '->find() throws a CommandNotFoundException if namespace does not exist, without alternatives');
595+
$this->assertEquals('There are no commands defined in the "Unknown-namespace" namespace.', $e->getMessage(), '->find() throws a NamespaceNotFoundException if namespace does not exist, without alternatives');
571596
}
572597

573598
try {
574599
$application->find('foo2:command');
575-
$this->fail('->find() throws a CommandNotFoundException if namespace does not exist');
600+
$this->fail('->find() throws a NamespaceNotFoundException if namespace does not exist');
576601
} catch (\Exception $e) {
577-
$this->assertInstanceOf('Symfony\Component\Console\Exception\CommandNotFoundException', $e, '->find() throws a CommandNotFoundException if namespace does not exist');
602+
$this->assertInstanceOf('Symfony\Component\Console\Exception\NamespaceNotFoundException', $e, '->find() throws a NamespaceNotFoundException if namespace does not exist');
578603
$this->assertCount(3, $e->getAlternatives());
579604
$this->assertContains('foo', $e->getAlternatives());
580605
$this->assertContains('foo1', $e->getAlternatives());
581606
$this->assertContains('foo3', $e->getAlternatives());
582-
$this->assertRegExp('/There are no commands defined in the "foo2" namespace./', $e->getMessage(), '->find() throws a CommandNotFoundException if namespace does not exist, with alternative');
583-
$this->assertRegExp('/foo/', $e->getMessage(), '->find() throws a CommandNotFoundException if namespace does not exist, with alternative : "foo"');
584-
$this->assertRegExp('/foo1/', $e->getMessage(), '->find() throws a CommandNotFoundException if namespace does not exist, with alternative : "foo1"');
585-
$this->assertRegExp('/foo3/', $e->getMessage(), '->find() throws a CommandNotFoundException if namespace does not exist, with alternative : "foo3"');
607+
$this->assertRegExp('/There are no commands defined in the "foo2" namespace./', $e->getMessage(), '->find() throws a NamespaceNotFoundException if namespace does not exist, with alternative');
608+
$this->assertRegExp('/foo/', $e->getMessage(), '->find() throws a NamespaceNotFoundException if namespace does not exist, with alternative : "foo"');
609+
$this->assertRegExp('/foo1/', $e->getMessage(), '->find() throws a NamespaceNotFoundException if namespace does not exist, with alternative : "foo1"');
610+
$this->assertRegExp('/foo3/', $e->getMessage(), '->find() throws a NamespaceNotFoundException if namespace does not exist, with alternative : "foo3"');
586611
}
587612
}
588613

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
use Symfony\Component\Console\Command\Command;
4+
use Symfony\Component\Console\Input\InputInterface;
5+
use Symfony\Component\Console\Output\OutputInterface;
6+
7+
class FooWithoutAliasCommand extends Command
8+
{
9+
protected function configure()
10+
{
11+
$this
12+
->setName('foo')
13+
->setDescription('The foo command')
14+
;
15+
}
16+
17+
protected function execute(InputInterface $input, OutputInterface $output)
18+
{
19+
$output->writeln('called');
20+
}
21+
}

src/Symfony/Component/Console/Tests/Fixtures/application_renderexception_doublewidth1.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11

2-
In ApplicationTest.php line 725:
2+
In ApplicationTest.php line 750:
33

44
エラーメッセージ
55

src/Symfony/Component/Console/Tests/Fixtures/application_renderexception_doublewidth1decorated.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11

2-
In ApplicationTest.php line 725:
2+
In ApplicationTest.php line 750:
33
 
44
 エラーメッセージ 
55
 

src/Symfony/Component/Console/Tests/Fixtures/application_renderexception_doublewidth2.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11

2-
In ApplicationTest.php line 739:
2+
In ApplicationTest.php line 764:
33

44
コマンドの実行中にエラーが
55
発生しました。

src/Symfony/Component/Console/Tests/Fixtures/application_renderexception_escapeslines.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11

2-
In ApplicationTest.php line 753:
2+
In ApplicationTest.php line 778:
33

44
dont break here <
55
info>!</info>

src/Symfony/Component/Console/Tests/Fixtures/application_renderexception_linebreaks.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11

2-
In ApplicationTest.php line 770:
2+
In ApplicationTest.php line 795:
33

44
line 1 with extra spaces
55
line 2

0 commit comments

Comments
 (0)
0