Initial commit: Pireon Admin — headless admin panel and public API
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>
This commit is contained in:
98
app/Console/Commands/SyncRepositories.php
Normal file
98
app/Console/Commands/SyncRepositories.php
Normal file
@@ -0,0 +1,98 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user