/`, а в нём flat-файлы Index. */ declare(strict_types=1); $root = dirname(__DIR__); $failures = []; foreach ([ '1/01_desk_1-source.avif', '1/01_desk_2-result.avif', '1/01_desk_3-thumb.avif', '1/05_mob_1-source.avif', '1/05_mob_2-result.avif', '1/05_mob_3-thumb.avif', '2/01_desk_1-source.avif', '2/05_mob_2-result.avif', ] as $relativePath) { if (!is_file($root . '/' . $relativePath)) { $failures[] = "Отсутствует Index-совместимый asset {$relativePath}."; } } foreach ([ 'images/demo', 'images/demo-2', ] as $obsoletePath) { if (is_dir($root . '/' . $obsoletePath)) { $failures[] = "Устаревший каталог {$obsoletePath} не должен оставаться в репозитории."; } } $template = (string) file_get_contents($root . '/template.php'); $examples = (string) file_get_contents($root . '/components/examples.php'); foreach ([ [$template, '"/{$indpic}"'], [$template, '01_desk_1-source.avif'], [$examples, "sprintf('%02d', \$number)"], [$examples, "'desk', '1-source'"], [$examples, "'mob', '3-thumb'"], ] as [$source, $expected]) { if (!str_contains($source, $expected)) { $failures[] = "Путь примеров должен использовать корневой flat-формат Index ({$expected})."; } } $workflow = (string) file_get_contents($root . '/.gitea/workflows/deploy.yml'); foreach ([ 'php bin/release-assets.php --stage-sets "$PRELAND_URL"', 'php bin/release-assets.php --remote "$PRELAND_URL"', 'php-imagick', 'Remove obsolete demo directories', ] as $requiredStageSmokeCheck) { if (!str_contains($workflow, $requiredStageSmokeCheck)) { $failures[] = "Stage-деплой обязан проверять публикацию {$requiredStageSmokeCheck}."; } } // #22: реальный runtime config выбирает наборы; удаление неиспользуемого /2/ // не должно блокировать выпуск. Обязательные файлы/размеры проверяет guard. require_once $root . '/bin/release-assets.php'; foreach (releaseFiles($root) as $file) { if (preg_match('~^(admin/|config\.json$|[0-9]+/)~', $file)) $failures[] = 'Runtime/приватный файл в поставке: ' . $file; } if (runtimeSetNumbers(['utm' => ['indpic' => ['default' => '3', 'weights' => ['3' => 1]]]]) !== [3]) $failures[] = 'Наборы должны определяться фактическим config'; if (!str_contains($workflow, '|[0-9]+/)')) { $failures[] = 'Stage-деплой не должен перезаписывать корневые наборы /N/: stage владеет их содержимым.'; } if (substr_count($workflow, 'while [ -n "$dir" ]; do') < 1) { $failures[] = 'SFTP-деплой должен создавать все родительские каталоги для новых наборов assets.'; } if ($failures !== []) { fwrite(STDERR, "FAILED\n- " . implode("\n- ", $failures) . "\n"); exit(1); } fwrite(STDOUT, "OK: Preland root sets match Index layout\n");