Resolve dependencies through the repositories the packages filter dropped

A partial build (`satis build satis.json web/ vendor/package`) narrows the
repository list down to the ones providing the requested packages. The
dependency pass then reused that narrowed list, so with
`require-dependencies` nothing the filtered package required could be
found -- packagist.org and every other repository had already been
dropped. Feed the dependency repository set the repositories the filter
removed, the same way the repository-URL filter already does.

Fixes #706
This commit is contained in:
dualfroz committed 2026-09-13 15:08:58 +02:00
1 parent 1a8cdb80c2
commit 8e2a075614
2 files changed
+56 -11

No files matched your search

+11 -3
View File
@@ -221,12 +221,17 @@ class PackageSelection
}
}
if ($this->hasFilterForPackages()) {
$repos = $this->filterPackages($repos);
$reposDroppedByPackagesFilter = [];
if (0 === count($repos)) {
if ($this->hasFilterForPackages()) {
$filteredRepos = $this->filterPackages($repos);
if (0 === count($filteredRepos)) {
throw new \InvalidArgumentException(sprintf('Could not find any repositories config with "name" matching your package(s) filter: %s', implode(', ', $this->packagesFilter)));
}
$reposDroppedByPackagesFilter = array_filter($repos, static fn ($repo) => !in_array($repo, $filteredRepos, true));
$repos = $filteredRepos;
}
$repositorySet = new RepositorySet($this->minimumStability, $stabilityFlags);
@@ -253,6 +258,9 @@ class PackageSelection
);
}
// the packages filter picks what to request, not who may answer a dependency
$this->addRepositories($repositorySet, $reposDroppedByPackagesFilter);
// additional repositories for dependencies
if (!$this->hasRepositoriesFilter() || true !== $this->repositoryFilterDep) {
$this->addRepositories($repositorySet, $this->getDepRepos($composer));
@@ -1401,6 +1401,32 @@ class PackageSelectionTest extends TestCase
);
}
/**
* `require-dependencies` resolves through the repositories the filter dropped.
*
* @see https://github.com/composer/satis/issues/706
*/
public function testSelectWithPackagesFilterStillResolvesDependencies(): void
{
$filteredPackage = 'vendor/filtered-package';
$dependency = 'vendor/dependency-package';
$this->runPackagesFilterSelection(
fn (string $workDir): array => [
$this->createLocalRepositoryConfig(
self::REPOSITORY_TYPE_PACKAGE,
$filteredPackage,
$workDir,
[$dependency => self::FIXTURE_VERSION]
),
$this->createLocalRepositoryConfig(self::REPOSITORY_TYPE_PACKAGE, $dependency, $workDir),
],
[$filteredPackage],
[$dependency, $filteredPackage],
['require-dependencies' => true]
);
}
/**
* Runs `select()` with a packages filter over a throwaway working directory
* and asserts which packages came out.
@@ -1408,18 +1434,20 @@ class PackageSelectionTest extends TestCase
* @param callable(string): list<array<string, mixed>> $buildRepositories
* @param list<string> $packagesFilter
* @param list<string> $expectedPackageNames
* @param array<string, mixed> $extraConfig
*/
private function runPackagesFilterSelection(
callable $buildRepositories,
array $packagesFilter,
array $expectedPackageNames,
array $extraConfig = [],
): void {
$filesystem = new Filesystem();
$workDir = sys_get_temp_dir() . '/satis-package-filter-' . uniqid('', true);
$filesystem->ensureDirectoryExists($workDir);
try {
$config = [
$config = $extraConfig + [
'name' => 'test/satis',
'homepage' => 'http://localhost',
'repositories' => $buildRepositories($workDir),
@@ -1448,19 +1476,28 @@ class PackageSelectionTest extends TestCase
/**
* Builds the repository fixture on disk and returns its Satis config entry.
*
* @param array<string, string> $requires
*
* @return array<string, mixed>
*/
private function createLocalRepositoryConfig(string $repositoryType, string $packageName, string $workDir): array
{
$composerJson = json_encode(
['name' => $packageName, 'version' => self::FIXTURE_VERSION],
\JSON_THROW_ON_ERROR
);
private function createLocalRepositoryConfig(
string $repositoryType,
string $packageName,
string $workDir,
array $requires = [],
): array {
$manifest = ['name' => $packageName, 'version' => self::FIXTURE_VERSION];
if ([] !== $requires) {
$manifest['require'] = $requires;
}
$composerJson = json_encode($manifest, \JSON_THROW_ON_ERROR);
if (self::REPOSITORY_TYPE_PACKAGE === $repositoryType) {
return [
'type' => self::REPOSITORY_TYPE_PACKAGE,
'package' => ['name' => $packageName, 'version' => self::FIXTURE_VERSION],
'package' => $manifest,
];
}