Modifiche'; public function handle(): int { $remote = trim((string) $this->option('remote')) ?: 'origin'; $branch = trim((string) $this->option('branch')) ?: 'main'; $force = (bool) $this->option('force'); if (! is_dir(base_path('.git'))) { $this->error('Repository Git non trovato nella base path corrente.'); $this->writeProgress(100, 'Repository Git non trovato', 'failed', 1); $this->persistSummary([ 'status' => 'failed', 'exit_code' => 1, 'message' => 'Repository Git non trovato', ]); return self::FAILURE; } $this->writeProgress(5, 'Preparazione sync da Gitea', 'running'); $currentBranch = $this->runGit(['rev-parse', '--abbrev-ref', 'HEAD']); $currentCommit = $this->runGit(['rev-parse', '--short', 'HEAD']); if ($currentBranch === null || $currentCommit === null) { $this->error('Impossibile leggere lo stato Git locale.'); $this->writeProgress(100, 'Impossibile leggere stato Git locale', 'failed', 1); $this->persistSummary([ 'status' => 'failed', 'exit_code' => 1, 'message' => 'Impossibile leggere stato Git locale', ]); return self::FAILURE; } $dirtyResult = Process::path(base_path())->run(['git', 'status', '--porcelain']); $isDirty = trim((string) $dirtyResult->output()) !== ''; if ($isDirty && ! $force) { $this->error('Working tree sporco: sync bloccata per evitare conflitti locali.'); $this->writeProgress(100, 'Working tree sporco: sync bloccata', 'failed', 1); $this->persistSummary([ 'status' => 'failed', 'exit_code' => 1, 'message' => 'Working tree sporco: sync bloccata', 'remote' => $remote, 'branch' => $branch, 'before_commit' => $currentCommit, 'working_tree_dirty' => true, ]); return self::FAILURE; } $this->info("Fetch da {$remote}..."); $this->writeProgress(18, 'Fetch remoto da Gitea', 'running'); $fetch = Process::path(base_path()) ->timeout(1800) ->run(['git', 'fetch', $remote]); if (! $fetch->successful()) { $this->line(trim((string) ($fetch->errorOutput() !== '' ? $fetch->errorOutput() : $fetch->output()))); $this->writeProgress(100, 'Fetch remoto fallito', 'failed', 1); $this->persistSummary([ 'status' => 'failed', 'exit_code' => 1, 'message' => 'Fetch remoto fallito', 'remote' => $remote, 'branch' => $branch, 'before_commit' => $currentCommit, 'working_tree_dirty' => false, ]); return self::FAILURE; } $this->writeProgress(32, 'Allineamento branch locale', 'running'); if ($currentBranch !== $branch) { $checkout = Process::path(base_path()) ->timeout(1800) ->run(['git', 'checkout', $branch]); if (! $checkout->successful()) { $this->line(trim((string) ($checkout->errorOutput() !== '' ? $checkout->errorOutput() : $checkout->output()))); $this->writeProgress(100, 'Checkout branch fallito', 'failed', 1); $this->persistSummary([ 'status' => 'failed', 'exit_code' => 1, 'message' => 'Checkout branch fallito', 'remote' => $remote, 'branch' => $branch, 'before_commit' => $currentCommit, 'working_tree_dirty' => false, ]); return self::FAILURE; } } $this->info("Pull ff-only da {$remote}/{$branch}..."); $this->writeProgress(48, 'Pull ff-only da Gitea', 'running'); $pull = Process::path(base_path()) ->timeout(1800) ->run(['git', 'pull', '--ff-only', $remote, $branch]); if (! $pull->successful()) { $this->line(trim((string) ($pull->errorOutput() !== '' ? $pull->errorOutput() : $pull->output()))); $this->writeProgress(100, 'Pull da Gitea fallito', 'failed', 1); $this->persistSummary([ 'status' => 'failed', 'exit_code' => 1, 'message' => 'Pull da Gitea fallito', 'remote' => $remote, 'branch' => $branch, 'before_commit' => $currentCommit, 'working_tree_dirty' => false, ]); return self::FAILURE; } $this->writeProgress(68, 'Rigenerazione changelog Git automatico', 'running'); File::ensureDirectoryExists(storage_path('app/support/generated')); $docsSync = Process::path(base_path()) ->timeout(1800) ->run([ 'bash', 'scripts/ops/netgescon-sync-git-changelog.sh', '--repo', base_path(), '--output', storage_path('app/support/generated/NETGESCON-GIT-AUTOCHANGELOG.md'), ]); if (! $docsSync->successful()) { $this->line(trim((string) ($docsSync->errorOutput() !== '' ? $docsSync->errorOutput() : $docsSync->output()))); $this->writeProgress(100, 'Rigenerazione changelog Git fallita', 'failed', 1); $this->persistSummary([ 'status' => 'failed', 'exit_code' => 1, 'message' => 'Rigenerazione changelog Git fallita', 'remote' => $remote, 'branch' => $branch, 'before_commit' => $currentCommit, 'working_tree_dirty' => false, ]); return self::FAILURE; } $this->writeProgress(76, 'Rigenerazione snapshot continuita sviluppo', 'running'); $snapshotExit = Artisan::call('netgescon:development-snapshot'); if ($snapshotExit !== 0) { $this->writeProgress(100, 'Rigenerazione snapshot sviluppo fallita', 'failed', 1); $this->persistSummary([ 'status' => 'failed', 'exit_code' => 1, 'message' => 'Rigenerazione snapshot sviluppo fallita', 'remote' => $remote, 'branch' => $branch, 'before_commit' => $currentCommit, 'working_tree_dirty' => false, ]); return self::FAILURE; } $this->writeProgress(82, 'Pulizia cache applicativa', 'running'); $this->callSilently('optimize:clear'); $newCommit = $this->runGit(['rev-parse', '--short', 'HEAD']) ?? $currentCommit; $remoteRef = $this->runGit(['rev-parse', '--short', 'refs/remotes/' . $remote . '/' . $branch]) ?? $newCommit; $this->persistSummary([ 'status' => 'completed', 'exit_code' => 0, 'message' => 'Sync Git completata', 'remote' => $remote, 'branch' => $branch, 'before_commit' => $currentCommit, 'after_commit' => $newCommit, 'remote_commit' => $remoteRef, 'working_tree_dirty' => false, ]); $this->info('Sync Git completata con successo.'); $this->writeProgress(100, 'Sync Git completata', 'completed', 0); return self::SUCCESS; } private function runGit(array $arguments): ?string { $result = Process::path(base_path()) ->timeout(1800) ->run(array_merge(['git'], $arguments)); if (! $result->successful()) { return null; } $output = trim((string) $result->output()); return $output !== '' ? $output : null; } private function writeProgress(int $percent, string $message, string $status, ?int $exitCode = null): void { $path = trim((string) $this->option('progress-file')); if ($path === '') { return; } $dir = dirname($path); if (! is_dir($dir)) { @mkdir($dir, 0775, true); } @file_put_contents($path, json_encode([ 'timestamp' => now()->toIso8601String(), 'percent' => max(0, min(100, $percent)), 'message' => $message, 'status' => $status, 'exit_code' => $exitCode, ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)); } private function persistSummary(array $payload): void { File::ensureDirectoryExists(storage_path('app/support/generated')); @file_put_contents( storage_path('app/support/generated/git-sync-last.json'), json_encode(array_merge([ 'synced_at' => now()->toIso8601String(), ], $payload), JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ); } }