groupRegistry->getWorkflow($workflowName); if ($workflow === null) { return WorkflowResult::error("Workflow '{$workflowName}' not found"); } return $this->executeWorkflowSteps($workflow, $context); } /** * Execute workflow steps */ public function executeWorkflowSteps(array $workflow, array $context = []): WorkflowResult { $this->output->writeLine("🔄 Starting workflow: {$workflow['name']}", ConsoleColor::BRIGHT_CYAN); if (!empty($workflow['description'])) { $this->output->writeLine($workflow['description'], ConsoleColor::GRAY); } $this->output->newLine(); // Check prerequisites if (!$this->checkPrerequisites($workflow['prerequisites'], $context)) { return WorkflowResult::error('Prerequisites not met'); } $results = []; $stepNumber = 1; $totalSteps = count($workflow['steps']); foreach ($workflow['steps'] as $step) { $workflowStep = $step instanceof WorkflowStep ? $step : WorkflowStep::fromArray($step); $this->output->writeLine( "Step {$stepNumber}/{$totalSteps}: {$workflowStep->getDescription() ?: $workflowStep->getCommand()}", ConsoleColor::BRIGHT_WHITE ); // Check if step should be executed if (!$workflowStep->shouldExecute($context)) { $this->output->writeLine(' ⏭️ Skipped (condition not met)', ConsoleColor::YELLOW); $stepNumber++; continue; } $stepResult = $this->executeStep($workflowStep, $context); $results[] = $stepResult; if ($stepResult->isSuccess()) { $this->output->writeLine(' ✅ Success', ConsoleColor::GREEN); } else { $message = " ❌ Failed: {$stepResult->getError()}"; if ($workflowStep->isOptional()) { $this->output->writeLine("{$message} (optional step)", ConsoleColor::YELLOW); } else { $this->output->writeLine($message, ConsoleColor::RED); if ($workflow['stopOnError']) { $this->output->newLine(); $this->output->writeLine('🛑 Workflow stopped due to error', ConsoleColor::RED); // Execute rollback if configured if (!empty($workflow['rollbackSteps'])) { $this->executeRollback($workflow['rollbackSteps'], $context); } return WorkflowResult::error("Step failed: {$stepResult->getError()}"); } } } $stepNumber++; } $this->output->newLine(); $this->output->writeLine('🎉 Workflow completed successfully!', ConsoleColor::BRIGHT_GREEN); return WorkflowResult::success($results); } /** * Execute a single workflow step */ private function executeStep(WorkflowStep $step, array $context): StepResult { $retryCount = 0; $maxRetries = $step->getRetryCount(); do { try { // Merge step environment with context $stepContext = array_merge($context, $step->getEnvironment()); // Build command arguments $args = ['console', $step->getCommand()]; foreach ($step->getParameters() as $param) { // Simple parameter substitution $args[] = $this->substituteVariables($param, $stepContext); } $exitCode = $this->commandRegistry->execute($args); if ($exitCode->value === 0) { return StepResult::success($step->getCommand()); } else { $error = "Command exited with code {$exitCode->value}"; if ($retryCount < $maxRetries) { $retryCount++; $this->output->writeLine( " ⏳ Retrying ({$retryCount}/{$maxRetries})...", ConsoleColor::YELLOW ); continue; } return StepResult::error($error); } } catch (\Exception $e) { $error = "Exception: {$e->getMessage()}"; if ($retryCount < $maxRetries) { $retryCount++; $this->output->writeLine( " ⏳ Retrying ({$retryCount}/{$maxRetries})...", ConsoleColor::YELLOW ); continue; } return StepResult::error($error); } } while ($retryCount <= $maxRetries); return StepResult::error('Max retries exceeded'); } /** * Execute rollback steps */ private function executeRollback(array $rollbackSteps, array $context): void { $this->output->writeLine('🔄 Executing rollback...', ConsoleColor::YELLOW); foreach ($rollbackSteps as $step) { $workflowStep = $step instanceof WorkflowStep ? $step : WorkflowStep::fromArray($step); $this->output->writeLine(" Rolling back: {$workflowStep->getCommand()}", ConsoleColor::GRAY); $result = $this->executeStep($workflowStep, $context); if ($result->isSuccess()) { $this->output->writeLine(' ✅ Rollback success', ConsoleColor::GREEN); } else { $this->output->writeLine(' ❌ Rollback failed', ConsoleColor::RED); } } } /** * Check workflow prerequisites */ private function checkPrerequisites(array $prerequisites, array $context): bool { if (empty($prerequisites)) { return true; } $this->output->writeLine('🔍 Checking prerequisites...', ConsoleColor::YELLOW); foreach ($prerequisites as $prerequisite) { // Simple prerequisite checking - can be extended if ($prerequisite === 'database') { $result = $this->checkDatabaseConnection(); } elseif ($prerequisite === 'migrations') { $result = $this->checkMigrations(); } else { $result = true; } if (!$result) { $this->output->writeLine("❌ Prerequisite failed: {$prerequisite}", ConsoleColor::RED); return false; } $this->output->writeLine("✅ {$prerequisite}", ConsoleColor::GREEN); } return true; } /** * Substitute variables in parameters */ private function substituteVariables(string $value, array $context): string { // Simple variable substitution: {{variable}} return preg_replace_callback('/\{\{(\w+)\}\}/', function($matches) use ($context) { return $context[$matches[1]] ?? $matches[0]; }, $value); } /** * Check database connection (placeholder) */ private function checkDatabaseConnection(): bool { // Implementation would check actual database connection return true; } /** * Check migrations (placeholder) */ private function checkMigrations(): bool { // Implementation would check migration status return true; } }