Laravel 13 + Filament 5 admin panel and REST API for a non-profit developer collective, backed by the Pireon OAuth identity server. The public site is a separate, server-rendered application consuming /api/public/v1. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
99 lines
3.1 KiB
PHP
99 lines
3.1 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Console\Commands;
|
|
|
|
use App\Jobs\SyncRepository;
|
|
use App\Models\Repository;
|
|
use App\Services\Git\GitException;
|
|
use App\Services\Git\GitManager;
|
|
use Illuminate\Console\Command;
|
|
use Illuminate\Support\Collection;
|
|
|
|
class SyncRepositories extends Command
|
|
{
|
|
protected $signature = 'repos:sync
|
|
{repository?* : Limit to these "owner/repo" names}
|
|
{--force : Sync even if refreshed recently}
|
|
{--sync : Run inline instead of dispatching to the queue}';
|
|
|
|
protected $description = 'Refresh repository stats and newcomer-friendly issues from their git provider';
|
|
|
|
public function handle(GitManager $git): int
|
|
{
|
|
$repositories = Repository::query()
|
|
->when(
|
|
$names = $this->argument('repository'),
|
|
fn ($q) => $q->whereIn('full_name', $names),
|
|
)
|
|
->unless(
|
|
$this->option('force') || $names,
|
|
// Skip anything refreshed recently so a manual sync is not
|
|
// immediately redone by the scheduled run.
|
|
fn ($q) => $q->where(fn ($sub) => $sub
|
|
->whereNull('last_synced_at')
|
|
->orWhere('last_synced_at', '<', now()->subMinutes((int) config('git.sync_ttl_minutes', 55)))),
|
|
)
|
|
->get();
|
|
|
|
if ($repositories->isEmpty()) {
|
|
$this->components->info('Nothing to sync.');
|
|
|
|
return self::SUCCESS;
|
|
}
|
|
|
|
// Running inline gives immediate, readable output — useful when
|
|
// setting things up or debugging a failing repository.
|
|
if ($this->option('sync')) {
|
|
return $this->runInline($git, $repositories);
|
|
}
|
|
|
|
$repositories->each(fn (Repository $repo) => SyncRepository::dispatch($repo));
|
|
|
|
$this->components->info("Queued {$repositories->count()} repositories for syncing.");
|
|
|
|
return self::SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @param Collection<int, Repository> $repositories
|
|
*/
|
|
protected function runInline(GitManager $git, $repositories): int
|
|
{
|
|
$failed = 0;
|
|
|
|
foreach ($repositories as $repository) {
|
|
try {
|
|
$synced = $git->sync($repository);
|
|
|
|
$this->components->twoColumnDetail(
|
|
$repository->full_name,
|
|
sprintf(
|
|
'<fg=green>%d★</> · %d issues · %s',
|
|
$synced->stars,
|
|
$synced->goodFirstIssues()->count(),
|
|
$synced->pushed_at?->diffForHumans() ?? 'never pushed',
|
|
),
|
|
);
|
|
} catch (GitException $e) {
|
|
$failed++;
|
|
|
|
$this->components->twoColumnDetail(
|
|
$repository->full_name,
|
|
'<fg=red>'.$e->getMessage().'</>',
|
|
);
|
|
}
|
|
}
|
|
|
|
if ($failed > 0) {
|
|
$this->newLine();
|
|
$this->components->warn("{$failed} repository(ies) failed to sync.");
|
|
|
|
return self::FAILURE;
|
|
}
|
|
|
|
return self::SUCCESS;
|
|
}
|
|
}
|