262 lines
9.6 KiB
PHP
262 lines
9.6 KiB
PHP
<?php
|
|
|
|
namespace App\Console\Commands;
|
|
|
|
use Illuminate\Support\Facades\Artisan;
|
|
use Illuminate\Console\Command;
|
|
use Illuminate\Support\Facades\File;
|
|
use Illuminate\Support\Facades\Process;
|
|
|
|
class NetgesconGitSyncCommand extends Command
|
|
{
|
|
protected $signature = 'netgescon:git-sync
|
|
{--remote=origin : Remote Git da usare}
|
|
{--branch=main : Branch da allineare}
|
|
{--force : Continua anche con working tree sporco}
|
|
{--progress-file= : File JSON dove scrivere lo stato avanzamento}';
|
|
|
|
protected $description = 'Allinea il nodo corrente da Gitea/Git e rigenera il materiale automatico per Supporto > 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)
|
|
);
|
|
}
|
|
} |