diff --git a/app/Console/Commands/NetgesconNodeRefreshCommand.php b/app/Console/Commands/NetgesconNodeRefreshCommand.php index 0acc5b1..e0827d5 100644 --- a/app/Console/Commands/NetgesconNodeRefreshCommand.php +++ b/app/Console/Commands/NetgesconNodeRefreshCommand.php @@ -15,6 +15,7 @@ class NetgesconNodeRefreshCommand extends Command {--force : Continua anche con working tree sporco lato sync} {--require-drive : Fallisce se il backup Drive non viene completato} {--skip-backup : Salta backup pre-update (solo test/debug)} + {--skip-composer : Salta composer install/autoload (solo recovery su nodi con vendor non scrivibile)} {--skip-migrate : Salta php artisan migrate --force} {--skip-maintenance : Salta php artisan down/up (solo test/debug)} {--skip-view-cache : Salta rebuild view cache} @@ -31,6 +32,7 @@ public function handle(): int $driveBackup = (bool) $this->option('drive'); $requireDrive = (bool) $this->option('require-drive'); $skipBackup = (bool) $this->option('skip-backup'); + $skipComposer = (bool) $this->option('skip-composer'); $skipMigrate = (bool) $this->option('skip-migrate'); $skipMaintenance = (bool) $this->option('skip-maintenance'); $skipViewCache = (bool) $this->option('skip-view-cache'); @@ -118,24 +120,29 @@ public function handle(): int $fullOutput[] = 'NODE REFRESH: netgescon:git-sync'; $fullOutput[] = $gitOutput; - $this->writeProgress(46, 'Composer install e autoload', 'running'); - $composerResult = $this->runShellStep([ - 'composer', - 'install', - '--no-interaction', - '--prefer-dist', - '--optimize-autoloader', - '--no-progress', - ]); - $fullOutput[] = 'NODE REFRESH: composer install --no-interaction --prefer-dist --optimize-autoloader --no-progress'; - $fullOutput[] = $composerResult['output']; + if (! $skipComposer) { + $this->writeProgress(46, 'Composer install e autoload', 'running'); + $composerResult = $this->runShellStep([ + 'composer', + 'install', + '--no-interaction', + '--prefer-dist', + '--optimize-autoloader', + '--no-progress', + ]); + $fullOutput[] = 'NODE REFRESH: composer install --no-interaction --prefer-dist --optimize-autoloader --no-progress'; + $fullOutput[] = $composerResult['output']; - if (! $composerResult['success']) { - $this->error('Composer install fallito.'); - $this->line($composerResult['output']); - $this->writeProgress(100, 'Composer install fallito', 'failed', $composerResult['exit_code']); + if (! $composerResult['success']) { + $this->error('Composer install fallito.'); + $this->line($composerResult['output']); + $this->writeProgress(100, 'Composer install fallito', 'failed', $composerResult['exit_code']); - return self::FAILURE; + return self::FAILURE; + } + } else { + $this->writeProgress(46, 'Composer install saltato (recovery)', 'running'); + $fullOutput[] = 'NODE REFRESH: composer install saltato via --skip-composer'; } $this->writeProgress(58, 'Build frontend se disponibile', 'running'); diff --git a/app/Filament/Pages/Supporto/Modifiche.php b/app/Filament/Pages/Supporto/Modifiche.php index e3895cd..bbceec9 100644 --- a/app/Filament/Pages/Supporto/Modifiche.php +++ b/app/Filament/Pages/Supporto/Modifiche.php @@ -358,6 +358,21 @@ public function runNodeRefreshFallback(): void $this->startNodeRefreshJob(true); } + public function runNodeRefreshSkipComposer(): void + { + if (! $this->canRunUpdate()) { + Notification::make() + ->title('Permessi insufficienti') + ->body('Solo super-admin/admin/amministratore possono lanciare il refresh completo del nodo.') + ->danger() + ->send(); + + return; + } + + $this->startNodeRefreshJob(true, true); + } + public function generateDevelopmentSnapshot(): void { if (! $this->canRunUpdate()) { @@ -1764,7 +1779,7 @@ private function startGitSyncJob(): void ->send(); } - private function startNodeRefreshJob(bool $skipMaintenance = false): void + private function startNodeRefreshJob(bool $skipMaintenance = false, bool $skipComposer = false): void { $jobId = now()->format('YmdHis') . '-' . Str::lower(Str::random(6)); $jobsDir = storage_path('app/support/update-jobs'); @@ -1778,17 +1793,21 @@ private function startNodeRefreshJob(bool $skipMaintenance = false): void $this->updateJobId = $jobId; $this->updateInProgress = true; $this->updateProgressPercent = 1; - $this->updateProgressMessage = $skipMaintenance - ? 'Preparazione refresh nodo da Gitea senza maintenance mode...' - : 'Preparazione refresh nodo da Gitea...'; + $this->updateProgressMessage = $skipComposer + ? 'Preparazione refresh nodo da Gitea senza maintenance e senza composer...' + : ($skipMaintenance + ? 'Preparazione refresh nodo da Gitea senza maintenance mode...' + : 'Preparazione refresh nodo da Gitea...'); $this->updateProgressStatus = 'running'; @file_put_contents($progressPath, json_encode([ 'timestamp' => now()->toIso8601String(), 'percent' => 1, - 'message' => $skipMaintenance - ? 'Preparazione refresh nodo da Gitea senza maintenance mode...' - : 'Preparazione refresh nodo da Gitea...', + 'message' => $skipComposer + ? 'Preparazione refresh nodo da Gitea senza maintenance e senza composer...' + : ($skipMaintenance + ? 'Preparazione refresh nodo da Gitea senza maintenance mode...' + : 'Preparazione refresh nodo da Gitea...'), 'status' => 'running', 'exit_code' => null, ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)); @@ -1818,6 +1837,10 @@ private function startNodeRefreshJob(bool $skipMaintenance = false): void $args[] = '--skip-maintenance'; } + if ($skipComposer) { + $args[] = '--skip-composer'; + } + if ($driveEnabled && $adminId > 0) { $args[] = '--drive'; $args[] = '--admin-id=' . $adminId; @@ -1849,9 +1872,11 @@ private function startNodeRefreshJob(bool $skipMaintenance = false): void Notification::make() ->title('Refresh nodo avviato') - ->body($skipMaintenance - ? 'Refresh nodo avviato senza maintenance mode. Usalo solo come percorso di riserva su macchine dove il blocco accessi non si attiva.' - : 'Sync da Gitea, migrate e rebuild cache verranno eseguiti direttamente sul nodo da browser.') + ->body($skipComposer + ? 'Refresh nodo avviato senza maintenance e senza composer. Usalo solo come recovery su macchine dove vendor non e scrivibile dal processo web.' + : ($skipMaintenance + ? 'Refresh nodo avviato senza maintenance mode. Usalo solo come percorso di riserva su macchine dove il blocco accessi non si attiva.' + : 'Sync da Gitea, migrate e rebuild cache verranno eseguiti direttamente sul nodo da browser.')) ->success() ->send(); } diff --git a/resources/views/filament/pages/supporto/aggiornamento-launcher.blade.php b/resources/views/filament/pages/supporto/aggiornamento-launcher.blade.php index bd344fa..7831d66 100644 --- a/resources/views/filament/pages/supporto/aggiornamento-launcher.blade.php +++ b/resources/views/filament/pages/supporto/aggiornamento-launcher.blade.php @@ -65,6 +65,9 @@ Refresh di riserva senza maintenance + + Recovery senza composer + Solo sync Git avanzata @@ -81,6 +84,10 @@ Se la macchina remota fallisce su Maintenance mode non attivata, prima allinea il nodo con Solo sync Git avanzata e poi usa Refresh di riserva senza maintenance. E un percorso di recupero per nodi dove il blocco accessi Laravel non parte correttamente. +
+ Se il nodo e gia allineato ma il refresh fallisce su vendor/composer/autoload_classmap.php: Permission denied, usa Recovery senza composer. Serve solo per chiudere migrate e cache rebuild quando non stai installando nuove dipendenze PHP. +
+ @if($this->updateInProgress)
@else