Abort purge when a file listed in "includes" is missing

This commit is contained in:
dualfroz committed 2026-10-14 19:40:29 +02:00
1 parent a12177f2cb
commit 39783bf4f3
3 files changed
+60 -5

No files matched your search

+1 -1
View File
@@ -77,7 +77,7 @@ class PurgeCommand extends BaseCommand
} }
$packageSelection = new PackageSelection($output, $outputDir, $config, false); $packageSelection = new PackageSelection($output, $outputDir, $config, false);
$packages = $packageSelection->load(); $packages = $packageSelection->load(true);
$satis_homepage = getenv('SATIS_HOMEPAGE'); $satis_homepage = getenv('SATIS_HOMEPAGE');
$prefix = sprintf( $prefix = sprintf(
+10 -4
View File
@@ -293,7 +293,7 @@ class PackageSelection
/** /**
* @return PackageInterface[] * @return PackageInterface[]
*/ */
public function load(): array public function load(bool $failOnMissingInclude = false): array
{ {
$packages = []; $packages = [];
$rootJsonFile = new JsonFile($this->filename); $rootJsonFile = new JsonFile($this->filename);
@@ -330,11 +330,17 @@ class PackageSelection
$includedJsonFile = new JsonFile($dirname . '/' . $file); $includedJsonFile = new JsonFile($dirname . '/' . $file);
if (!$includedJsonFile->exists()) { if (!$includedJsonFile->exists()) {
$this->output->writeln(sprintf( $message = sprintf(
'<error>File \'%s\' does not exist, defined in "includes" in \'%s\'</error>', 'File \'%s\' does not exist, defined in "includes" in \'%s\'',
$includedJsonFile->getPath(), $includedJsonFile->getPath(),
$rootJsonFile->getPath() $rootJsonFile->getPath()
)); );
if ($failOnMissingInclude) {
throw new \RuntimeException($message);
}
$this->output->writeln('<error>' . $message . '</error>');
continue; continue;
} }
@@ -534,6 +534,55 @@ class PurgeCommandTest extends TestCase
self::assertStringContainsString('Removed empty directory', $tester->getDisplay()); self::assertStringContainsString('Removed empty directory', $tester->getDisplay());
} }
/**
* A concurrent build can rewrite packages.json and drop the include it points to;
* the archives listed in that include are still needed and must not be purged.
*/
#[TestDox('execute() aborts without removing archives when an included file is missing')]
public function testExecuteAbortsWhenIncludedFileIsMissing(): void
{
$outputDir = vfsStream::url('satis/output-missing-include');
mkdir($outputDir);
$archiveDir = $outputDir . '/dist';
mkdir($archiveDir . '/vendor', 0755, true);
$archiveFile = $archiveDir . '/vendor/package.tar.gz';
file_put_contents($archiveFile, 'a');
$includeFile = 'include/all$missing.json';
$this->writeOutputRepository($outputDir, $this->packageEntry(
'vendor/package',
'1.0.0',
'https://example.com/dist/vendor/package.tar.gz'
), $includeFile);
unlink($outputDir . '/' . $includeFile);
$this->writeSatisConfig([
'name' => 'test/satis-repo',
'homepage' => 'https://example.com',
'output-dir' => $outputDir,
'archive' => [
'directory' => 'dist',
'prefix-url' => 'https://example.com',
],
]);
$tester = $this->createTester();
$exception = null;
try {
$tester->execute([
'file' => $this->configPath,
'output-dir' => $outputDir,
]);
} catch (\RuntimeException $exception) {
}
self::assertInstanceOf(\RuntimeException::class, $exception);
self::assertStringContainsString($includeFile . '\' does not exist', $exception->getMessage());
self::assertFileExists($archiveFile);
}
// --- Dry-run --- // --- Dry-run ---
#[TestDox('execute() does not remove archives or empty dirs when dry-run is enabled')] #[TestDox('execute() does not remove archives or empty dirs when dry-run is enabled')]