feat(Deployment): Integrate Ansible deployment via PHP deployment pipeline

- Create AnsibleDeployStage using framework's Process module for secure command execution
- Integrate AnsibleDeployStage into DeploymentPipelineCommands for production deployments
- Add force_deploy flag support in Ansible playbook to override stale locks
- Use PHP deployment module as orchestrator (php console.php deploy:production)
- Fix ErrorAggregationInitializer to use Environment class instead of $_ENV superglobal

Architecture:
- BuildStage → AnsibleDeployStage → HealthCheckStage for production
- Process module provides timeout, error handling, and output capture
- Ansible playbook supports rollback via rollback-git-based.yml
- Zero-downtime deployments with health checks
This commit is contained in:
2025-10-26 14:08:07 +01:00
parent a90263d3be
commit 3b623e7afb
170 changed files with 19888 additions and 575 deletions

View File

@@ -14,7 +14,7 @@ use App\Framework\Database\Migration\ValueObjects\MemoryThresholds;
use App\Framework\Database\Migration\ValueObjects\MigrationTableConfig;
use App\Framework\Database\Platform\DatabasePlatform;
use App\Framework\DateTime\Clock;
use App\Framework\Exception\ErrorCode;
use App\Framework\Exception\Core\DatabaseErrorCode;
use App\Framework\Exception\ExceptionContext;
use App\Framework\Exception\FrameworkException;
use App\Framework\Logging\Logger;
@@ -22,6 +22,7 @@ use App\Framework\Performance\MemoryMonitor;
use App\Framework\Performance\OperationTracker;
use App\Framework\Performance\PerformanceReporter;
use App\Framework\Performance\Repository\PerformanceMetricsRepository;
use App\Framework\Ulid\UlidGenerator;
final readonly class MigrationRunner
{
@@ -41,6 +42,7 @@ final readonly class MigrationRunner
private ConnectionInterface $connection,
private DatabasePlatform $platform,
private Clock $clock,
private UlidGenerator $ulidGenerator,
?MigrationTableConfig $tableConfig = null,
?Logger $logger = null,
?OperationTracker $operationTracker = null,
@@ -107,7 +109,7 @@ final readonly class MigrationRunner
$totalMigrations = $orderedMigrations->count();
// Start batch tracking
$batchOperationId = 'migration_batch_' . uniqid();
$batchOperationId = 'migration_batch_' . $this->ulidGenerator->generate();
$this->performanceTracker->startBatchOperation($batchOperationId, $totalMigrations);
$currentPosition = 0;
@@ -198,7 +200,7 @@ final readonly class MigrationRunner
$migrationContext = $this->errorAnalyzer->analyzeMigrationContext($migration, $version, $e);
throw FrameworkException::create(
ErrorCode::DB_MIGRATION_FAILED,
DatabaseErrorCode::MIGRATION_FAILED,
"Migration {$version} failed: {$e->getMessage()}"
)->withContext(
ExceptionContext::forOperation('migration.execute', 'MigrationRunner')
@@ -252,7 +254,7 @@ final readonly class MigrationRunner
$totalRollbacks = count($versionsToRollback);
// Start rollback batch tracking
$rollbackBatchId = 'rollback_batch_' . uniqid();
$rollbackBatchId = 'rollback_batch_' . $this->ulidGenerator->generate();
$this->performanceTracker->startBatchOperation($rollbackBatchId, $totalRollbacks);
$currentPosition = 0;
@@ -269,7 +271,7 @@ final readonly class MigrationRunner
// CRITICAL SAFETY CHECK: Ensure migration supports safe rollback
if (! $migration instanceof SafelyReversible) {
throw FrameworkException::create(
ErrorCode::DB_MIGRATION_NOT_REVERSIBLE,
DatabaseErrorCode::MIGRATION_NOT_REVERSIBLE,
"Migration {$version} does not support safe rollback"
)->withContext(
ExceptionContext::forOperation('migration.rollback', 'MigrationRunner')
@@ -353,7 +355,7 @@ final readonly class MigrationRunner
$recoveryHints = $this->errorAnalyzer->generateRollbackRecoveryHints($migration, $e, $remainingRollbacks);
throw FrameworkException::create(
ErrorCode::DB_MIGRATION_ROLLBACK_FAILED,
DatabaseErrorCode::MIGRATION_ROLLBACK_FAILED,
"Rollback failed for migration {$version}: {$e->getMessage()}"
)->withContext(
ExceptionContext::forOperation('migration.rollback', 'MigrationRunner')
@@ -437,7 +439,7 @@ final readonly class MigrationRunner
// Throw exception if critical issues found
if (! empty($criticalIssues)) {
throw FrameworkException::create(
ErrorCode::DB_MIGRATION_PREFLIGHT_FAILED,
DatabaseErrorCode::MIGRATION_PREFLIGHT_FAILED,
'Pre-flight checks failed with critical issues'
)->withData([
'critical_issues' => $criticalIssues,