ADD Deployment csomagoló seeder-felismerés a teendők közé

Éles használat közben derült ki: a csomagba került egy seeder, de a _TEENDOK.md nem
szólt róla. A seeder felmásolása önmagában nem csinál semmit, tehát csendben kimaradt
egy lépés - pont az a hibatípus, ami ellen az egész eszköz készült.

- config: új attention csoport a database/seeders/* útvonalakra
- a felületen figyelmeztetés, a teendőkben a konkrét osztálynévvel:
  php artisan db:seed --class=<Osztály>
- mellé egy feltételes cache-lépés: a Pennant purge Eloquent mentésnél NEM kell (a
  FeatureFlagObserver::saved() elvégzi), csak query builderes írás után; a laratrust
  cache pedig csak szerepkör/jogosultság hozzárendelés változásakor, mert a saját
  cache-ét a felhasználóhoz kötve tárolja

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
E98Developer 2026-08-16 22:23:11 +02:00
parent 9bc723bd83
commit c8d5e01490
4 changed files with 74 additions and 0 deletions

View File

@ -108,6 +108,17 @@ private function warnings(array $copied, array $deleted, int $excludedCount, ?ar
]; ];
} }
$seeders = $this->matching($copied, 'seeder');
if ($seeders !== []) {
$warnings[] = [
'level' => 'warning',
'title' => sprintf('Seeder a csomagban (%d db)', count($seeders)),
'body' => 'A seeder felmásolása önmagában nem csinál semmit - el kell dönteni, hogy le kell-e futtatni a célgépen. '
.'Ha feature flageket ír, a lefutása után azok azonnal hatnak.',
];
}
if ($this->matching($copied, 'composer') !== []) { if ($this->matching($copied, 'composer') !== []) {
$warnings[] = [ $warnings[] = [
'level' => 'warning', 'level' => 'warning',

View File

@ -4,6 +4,7 @@
use Illuminate\Filesystem\Filesystem; use Illuminate\Filesystem\Filesystem;
use Illuminate\Support\Carbon; use Illuminate\Support\Carbon;
use Illuminate\Support\Str;
use RuntimeException; use RuntimeException;
use ZipArchive; use ZipArchive;
@ -310,6 +311,24 @@ private function writeInstructions(string $path, array $manifest, array $target)
$steps[] = 'Futtasd a célgépen: `php artisan migrate`'; $steps[] = 'Futtasd a célgépen: `php artisan migrate`';
} }
if (str_contains($warning['title'], 'Seeder')) {
$seeders = $this->seederClasses($manifest);
$steps[] = sprintf(
'Seeder változott (%s). A felmásolás önmagában NEM futtatja le - ha idempotens '
.'(`updateOrCreate`/`firstOrCreate`), futtasd: %s',
implode(', ', $seeders),
implode(' ', array_map(fn (string $class): string => '`php artisan db:seed --class='.$class.'`', $seeders)),
);
// A projekt FeatureFlagObserver-e Eloquent mentéskor magától purge-öl, ezért
// ezt nem kötelező lépésként, hanem feltételes ellenőrzésként írjuk ki.
$steps[] = 'Ha a seeder feature flageket írt **Eloquent modellen keresztül**, a Pennant cache-t a '
.'`FeatureFlagObserver` magától üríti. Query builderes írás (`->update()`) esetén viszont kell: '
.'`php artisan pennant:purge`. Ha szerepkör/jogosultság **hozzárendelés** változott, a laratrust '
.'cache-hez: `php artisan cache:clear`.';
}
if (str_contains($warning['title'], 'composer')) { if (str_contains($warning['title'], 'composer')) {
$steps[] = 'Futtasd a célgépen: `composer install --no-dev` (a vendor/ nincs a csomagban)'; $steps[] = 'Futtasd a célgépen: `composer install --no-dev` (a vendor/ nincs a csomagban)';
} }
@ -428,6 +447,28 @@ private function createZip(string $path, string $name): ?string
return $zipPath; return $zipPath;
} }
/**
* A csomagban lévő seeder fájlok osztálynevei.
*
* @param array<string, mixed> $manifest
* @return array<int, string>
*/
private function seederClasses(array $manifest): array
{
/** @var array<int, string> $patterns */
$patterns = (array) config('deployment.attention.seeder', []);
$classes = [];
foreach ($manifest['files'] as $file) {
if (Str::is($patterns, $file['path'])) {
$classes[] = pathinfo($file['path'], PATHINFO_FILENAME);
}
}
return $classes;
}
/** /**
* Mindig LF sorvéggel írunk: a csomag Windowson készül, de Linux célgépre megy. * Mindig LF sorvéggel írunk: a csomag Windowson készül, de Linux célgépre megy.
*/ */

View File

@ -87,6 +87,7 @@
*/ */
'attention' => [ 'attention' => [
'migration' => ['database/migrations/*'], 'migration' => ['database/migrations/*'],
'seeder' => ['database/seeders/*'],
'composer' => ['composer.json', 'composer.lock'], 'composer' => ['composer.json', 'composer.lock'],
'asset' => [ 'asset' => [
'resources/js/*', 'resources/js/*',

View File

@ -70,6 +70,7 @@ function deploymentTestRepository(): array
File::makeDirectory($path.'/app', 0777, true); File::makeDirectory($path.'/app', 0777, true);
File::makeDirectory($path.'/database/migrations', 0777, true); File::makeDirectory($path.'/database/migrations', 0777, true);
File::makeDirectory($path.'/database/seeders', 0777, true);
deploymentGit($path, ['init']); deploymentGit($path, ['init']);
deploymentGit($path, ['config', 'user.email', 'teszt@example.com']); deploymentGit($path, ['config', 'user.email', 'teszt@example.com']);
@ -86,6 +87,7 @@ function deploymentTestRepository(): array
File::put($path.'/app/Elso.php', "<?php\n// elso modositva\n"); File::put($path.'/app/Elso.php', "<?php\n// elso modositva\n");
File::put($path.'/app/Árlista.php', "<?php\n// ekezetes\n"); File::put($path.'/app/Árlista.php', "<?php\n// ekezetes\n");
File::put($path.'/database/migrations/2026_01_01_000000_teszt.php', "<?php\n// migracio\n"); File::put($path.'/database/migrations/2026_01_01_000000_teszt.php', "<?php\n// migracio\n");
File::put($path.'/database/seeders/TesztSeeder.php', "<?php\n// seeder\n");
File::put($path.'/.env', "APP_KEY=titok\n"); File::put($path.'/.env', "APP_KEY=titok\n");
deploymentGit($path, ['add', '-A', '-f']); deploymentGit($path, ['add', '-A', '-f']);
deploymentGit($path, ['commit', '-m', "második commit\n\nA törzsben említett árlista részlet."]); deploymentGit($path, ['commit', '-m', "második commit\n\nA törzsben említett árlista részlet."]);
@ -249,11 +251,30 @@ function deploymentCleanup(string $path): void
$titles = collect($changeSet['warnings'])->pluck('title')->implode(' | '); $titles = collect($changeSet['warnings'])->pluck('title')->implode(' | ');
expect($titles)->toContain('Migráció') expect($titles)->toContain('Migráció')
->and($titles)->toContain('Seeder')
->and($titles)->toContain('Törlendő fájl'); ->and($titles)->toContain('Törlendő fájl');
deploymentCleanup($repository['path']); deploymentCleanup($repository['path']);
}); });
test('a teendők között szerepel a seeder futtatása a konkrét osztálynévvel', function () {
deploymentAllowEnvironment();
$repository = deploymentTestRepository();
[$first, , $third] = $repository['commits'];
$package = app(DeploymentPackageBuilder::class)->build('e2e', 'main', $first, $third);
$teendok = File::get($package['path'].'/_TEENDOK.md');
expect($teendok)->toContain('php artisan db:seed --class=TesztSeeder')
// A seeder puszta felmásolása nem futtatja le - ezt ki kell mondani.
->and($teendok)->toContain('NEM futtatja le')
// A Pennant purge feltételes: Eloquent mentésnél a FeatureFlagObserver elvégzi.
->and($teendok)->toContain('pennant:purge')
->and($teendok)->toContain('cache:clear');
deploymentCleanup($repository['path']);
});
test('az érvénytelen commit azonosítót nem adja tovább a gitnek', function () { test('az érvénytelen commit azonosítót nem adja tovább a gitnek', function () {
$repository = deploymentTestRepository(); $repository = deploymentTestRepository();