-
Notifications
You must be signed in to change notification settings - Fork 37
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow commands to call other commands #64
Comments
Yes, we definitely this functionality. I'm ambivalent about adding an annotation for this feature, though. I think it might be better to simply have folks use php to call the commands they want to invoke. Something like: /**
* @command tests:all
*
* @calls tests:behat
* @calls tests:phpunit
*/
public function testsAll() {
$result = $invoker->invoke('tests:behat');
return $result;
} This would give the caller a chance to do something with the result, if needed. The advantage of the annotation is that the Undecided about the best choice here; I'm okay with moving forward with |
I think I'd prefer to go with the Let's assume that a command needs to call multiple other commands, and fail if any one of those other commands fail. To do this with PHP you'd need: <?php
/**
* @command tests:all
*/
public function testsAll() {
$result = $invoker->invoke('tests:behat');
if (!$result) {
return 1;
}
$result = $invoker->invoke('tests:phpunit');
if (!$result) {
return 1;
}
$result = $invoker->invoke('tests:custom');
if (!$result) {
return 1;
}
} This quickly becomes cumbersome. Ideally the responsibility of handling failure and returning an exit code would be moved out of the calling command itself. Using an annotation accomplishes this. /**
* @command tests:all
*
* @calls tests:behat
* @calls tests:phpunit
* @calls tests:custom
*/
public function testsAll() {
} |
OK, how about something like this:
Collections will already abort if one step fails. We'd just need a task implementation that had a reference to the Symfony Application -- easy enough to build that. |
That ^^ would have to move to the Robo PHP project, of course. |
Drush does a lot of this. For our needs, I think using straight PHP per #64 (comment) is our best fit. |
This would be wonderful to have implemented - in any form. As mentioned by @grasmash , hooks do not (understandably) fire with $this->commandMethod(). However, annotations completely aside - I don't think this is possible at all, correct? To leverage the hook system, in rare cases where we want to run a command from within a command we have (unfortunately) resorted to standardizing on using exec() to run a second robo from within robo to allow the command hooks to fire. Many Thanks! |
With a reference to the |
I ran into a use case where it would be very handy if I were able to call other commands, so I found this issue. I like the idea of the command caller task as suggested by Greg Anderson a few comments above. For me the I think one of the problem is that the I think the real command class instance should be created in the |
<?php
use Robo\Common\ConfigAwareTrait;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Yaml\Yaml;
class RoboFile extends \Robo\Tasks implements \Robo\Contract\ConfigAwareInterface
{
use ConfigAwareTrait;
/**
* @var int
*/
protected static $instanceCounter = 0;
/**
* @var int
*/
protected $instanceIndex = 0;
public function __construct()
{
static::$instanceCounter++;
$this->instanceIndex = static::$instanceCounter;
}
/**
* @command main:app-get-run
*/
public function mainAppGetRun(
?string $arg01 = null,
array $options = [
'option-01' => '',
]
) {
$this->action(
'-= Main App Get Run in action =-',
$arg01,
$options['option-01']
);
/** @var \Robo\Application $app */
$app = $this
->getContainer()
->get('application');
$sub01Command = $app->get('sub:01');
$sub01InputDefinition = $sub01Command->getDefinition();
$sub01InputParameters = [
'arg01' => 'subArg01Value',
'--option-01' => 'subOption01Value',
];
$sub01Input = new ArrayInput($sub01InputParameters, $sub01InputDefinition);
$sub01Command->run($sub01Input, $this->output());
}
/**
* @command main:app-run
*/
public function mainAppRun(
?string $arg01 = null,
array $options = [
'option-01' => '',
]
) {
$this->action(
'-= Main App Run in action =-',
$arg01,
$options['option-01']
);
/** @var \Robo\Application $app */
$app = $this
->getContainer()
->get('application');
$sub01Command = $app->get('sub:01');
$sub01InputParameters = [
'command' => $sub01Command->getName(),
'arg01' => 'subArg01Value',
'--option-01' => 'subOption01Value',
'--define' => 'environment=sub01Overridden',
];
$sub01Input = new ArrayInput($sub01InputParameters);
$app->run($sub01Input, $this->output());
}
/**
* @command sub:01
*/
public function sub01(
?string $arg01 = null,
array $options = [
'option-01' => null,
]
) {
$this->action(
'-= Sub 01 in action =-',
$arg01,
$options['option-01']
);
}
protected function action(string $header, ?string $arg01 = null, ?string $option01 = null)
{
$input = $this->input();
$output = $this->output();
$output->writeln($header);
$output->writeln("\$arg01 = $arg01");
$output->writeln("\$option01 = $option01");
$output->writeln('---');
$output->write(Yaml::dump($input->getArguments(), 42));
$output->writeln('---');
$output->write(Yaml::dump($input->getOptions(), 42));
$output->writeln('...');
$output->writeln('');
}
} Run:
In this case you can use the passed arguments of the In my use case I want modify the behaviour of a command in certain circumstances <?php
/**
* @hook option my:xyz
*/
public function myXyzHookOption(Command $command) {
if ($this->getConfig()->get('foo') === 'bar') {
$command->setDescription('Something else.');
$this->hookOptionAddArguments(
$command,
[
'arg01' => [
'name' => 'arg01',
'mode' => InputArgument::REQUIRED,
'description' => 'Useful description',
'default' => NULL,
],
]
);
}
}
/**
* @command my:xyz
*/
public function myXyz() {
if ($this->getConfig()->get('foo') === 'bar') {
// ...
} else {
// ...
}
} In this case I can't explicitly define the parameters of the PHP method, so I have to use the |
See also consolidation/robo#675 I think Robo is likely the better layer to provide this sort of functionality. The above PR has been approved, but I am still considering improvements (e.g. an invoker) to make it more convenient. |
I think you can't solve this in Robo (or any kind of top level Application layer) while |
We have been accomplishing this for some time using the following trait: https://github.com/wieni/wmscaffold/blob/release/v1/src/Commands/RunCommandTrait.php. Usage example: <?php
namespace Drupal\some_module\Commands;
use Consolidation\SiteAlias\SiteAliasManagerAwareInterface;
use Drush\Commands\DrushCommands;
use Symfony\Component\Process\Exception\ProcessFailedException;
class FreshCommands extends DrushCommands implements SiteAliasManagerAwareInterface
{
use RunCommandTrait;
/**
* Bring your site up to date with the latest file changes
*
* @command fresh
* @aliases fr
* @bootstrap none
*/
public function fresh()
{
try {
$this->drush('cache-rebuild');
$this->drush('updatedb', ['no-post-updates' => true]);
$this->drush('config-import');
$this->drush('locale:check');
$this->drush('locale:update');
$this->drush('updatedb');
$this->drush('cache-rebuild');
} catch (ProcessFailedException $e) {
return $e->getProcess()->getExitCode();
}
}
/**
* Bring your site up to date with the latest file changes
* and export any new configuration from module update hooks.
*
* @command post-update
* @aliases pu
* @bootstrap none
*/
public function postUpdate()
{
try {
$this->drush('cache-rebuild');
$this->drush('locale:check');
$this->drush('locale:update');
$this->drush('updatedb');
$this->drush('config-export');
$this->drush('cache-rebuild');
} catch (ProcessFailedException $e) {
return $e->getProcess()->getExitCode();
}
}
} |
I would like to be able to calls other commands from my annotated command using an annotation. E.g.,
In this example, using
@calls tests:behat
would cause thetests:behat
command to be executed prior the the body oftestsAll()
.This is better than simply calling
$this->testsBehat()
from$this->testsAll()
because it will invoke the hooks for$this->testsBehat()
.The text was updated successfully, but these errors were encountered: