55use Bref \Cli \BrefCloudClient ;
66use Bref \Cli \Cli \IO ;
77use Bref \Cli \Cli \Styles ;
8- use Bref \Cli \Config ;
98use JsonException ;
109use Symfony \Component \Console \Input \InputArgument ;
1110use Symfony \Component \Console \Input \InputInterface ;
12- use Symfony \Component \Console \Input \InputOption ;
1311use Symfony \Component \Console \Output \OutputInterface ;
12+ use function Amp \delay ;
1413
15- class Command extends \ Symfony \ Component \ Console \ Command \Command
14+ class Command extends ApplicationCommand
1615{
1716 protected function configure (): void
1817 {
1918 $ this
2019 ->setName ('command ' )
2120 ->setDescription ('Run a CLI command in the deployed application ' )
22- ->addOption ('config ' , 'c ' , InputOption::VALUE_REQUIRED , 'The location of the configuration file to use ' )
23- ->addArgument ('args ' , InputArgument::OPTIONAL , 'The command to run ' , '' )
24- ->addOption ('app ' , null , InputOption::VALUE_REQUIRED , 'The app name (if outside of a project directory) ' )
25- ->addOption ('env ' , 'e ' , InputOption::VALUE_REQUIRED , 'The environment to deploy to ' , 'dev ' );
21+ ->addArgument ('args ' , InputArgument::OPTIONAL , 'The command to run ' , '' );
22+ parent ::configure ();
2623 }
2724
2825 protected function execute (InputInterface $ input , OutputInterface $ output ): int
2926 {
30- /** @var string|null $configFileName */
31- $ configFileName = $ input ->getOption ('config ' );
27+ [
28+ 'appName ' => $ appName ,
29+ 'environmentName ' => $ environmentName ,
30+ 'team ' => $ team ,
31+ ] = $ this ->parseStandardOptions ($ input );
32+
3233 /** @var string $command */
3334 $ command = $ input ->getArgument ('args ' );
34- /** @var string $environment */
35- $ environment = $ input ->getOption ('env ' );
36- /** @var string|null $appName */
37- $ appName = $ input ->getOption ('app ' );
38- if (! $ appName ) {
39- $ appName = Config::loadConfig ($ configFileName , $ environment , null )['name ' ];
40- }
35+
36+ IO ::spin ('starting command ' );
4137
4238 $ brefCloud = new BrefCloudClient ;
43- $ result = $ brefCloud ->startCommand ($ appName , $ environment , $ command );
44-
45- if ($ result ['success ' ]) {
46- IO ::writeln ($ result ['output ' ]);
47- } else {
48- try {
49- $ errorDetails = json_decode ($ result ['output ' ], true , 512 , JSON_THROW_ON_ERROR );
50- if (is_array ($ errorDetails ) && isset ($ errorDetails ['errorType ' ], $ errorDetails ['errorMessage ' ])) {
51- $ message = nl2br ($ errorDetails ['errorMessage ' ]);
52- IO ::writeln ([
53- '' ,
54- Styles::red ('ERROR ' ),
55- Styles::gray ($ errorDetails ['errorType ' ]),
56- '' ,
57- $ message ,
58- ]);
59- if (isset ($ errorDetails ['stackTrace ' ]) && is_array ($ errorDetails ['stackTrace ' ])) {
60- IO ::verbose ($ errorDetails ['stackTrace ' ]);
61- }
62- } else {
63- IO ::writeln (Styles::red ($ result ['output ' ]));
64- }
65- } catch (JsonException ) {
66- IO ::writeln (Styles::red ($ result ['output ' ]));
39+ $ environment = $ brefCloud ->findEnvironment ($ team , $ appName , $ environmentName );
40+ $ id = $ brefCloud ->startCommand ($ environment ['id ' ], $ command );
41+
42+ IO ::spin ('running ' );
43+
44+ // Timeout after 2 minutes and 10 seconds
45+ $ timeout = 130 ;
46+ $ startTime = time ();
47+
48+ while (true ) {
49+ $ invocation = $ brefCloud ->getCommand ($ id );
50+
51+ if ($ invocation ['status ' ] === 'success ' ) {
52+ IO ::spinClear ();
53+ IO ::writeln ($ invocation ['output ' ]);
54+ return 0 ;
55+ }
56+
57+ if ($ invocation ['status ' ] === 'failed ' ) {
58+ IO ::spinClear ();
59+ $ this ->writeErrorDetails ($ invocation ['output ' ]);
60+ return 1 ;
61+ }
62+
63+ if ((time () - $ startTime ) > $ timeout ) {
64+ IO ::spinClear ();
65+ IO ::writeln (Styles::red ('Timed out ' ));
66+ IO ::writeln (Styles::gray ('The execution timed out after 2 minutes, the command might still be running ' ));
67+ return 1 ;
6768 }
69+
70+ delay (1 );
6871 }
72+ }
73+
74+ private function writeErrorDetails (string $ output ): void
75+ {
76+ try {
77+ $ errorDetails = json_decode ($ output , true , 512 , JSON_THROW_ON_ERROR );
78+ if (! is_array ($ errorDetails )
79+ || ! isset ($ errorDetails ['errorType ' ], $ errorDetails ['errorMessage ' ])
80+ || ! is_string ($ errorDetails ['errorType ' ])
81+ || ! is_string ($ errorDetails ['errorMessage ' ])) {
82+ IO ::writeln (Styles::red ($ output ));
83+ return ;
84+ }
85+
86+ $ errorType = $ errorDetails ['errorType ' ];
87+ if ($ errorType === 'Bref\ConsoleRuntime\CommandFailed ' ) {
88+ // No need to show this class, it's noise
89+ $ errorType = '' ;
90+ }
6991
70- return $ result ['success ' ] ? 0 : 1 ;
92+ IO ::writeln ([
93+ '' ,
94+ Styles::bold (Styles::red ('ERROR ' )) . ' ' . Styles::gray ($ errorType ),
95+ '' ,
96+ $ errorDetails ['errorMessage ' ],
97+ ]);
98+ if (isset ($ errorDetails ['stackTrace ' ]) && is_array ($ errorDetails ['stackTrace ' ])) {
99+ IO ::verbose ($ errorDetails ['stackTrace ' ]);
100+ }
101+ } catch (JsonException ) {
102+ IO ::writeln (Styles::red ($ output ));
103+ }
71104 }
72105}
0 commit comments