function TemplateProjectTestBase::createVendorRepository

Creates a Composer repository for all dependencies of the test project.

We always reference third-party dependencies (i.e., any package that isn't part of Drupal core) from the main project which is running this test.

Packages that are part of Drupal core -- such as `drupal/core`, `drupal/core-composer-scaffold`, and so on -- are expected to have been copied into the workspace directory, so that we can modify them as needed.

The file will be written to WORKSPACE_DIR/vendor.json.

Parameters

string[] $versions: (optional) The versions of specific packages, keyed by package name. Versions of packages not in this array will be determined first by looking for a `version` key in the package's composer.json, then by calling \Composer\InstalledVersions::getPrettyVersion(). If none of that works, `dev-main` will be used as the package's version.

File

core/modules/package_manager/tests/src/Build/TemplateProjectTestBase.php, line 405

Class

TemplateProjectTestBase
Base class for tests which create a test site from a core project template.

Namespace

Drupal\Tests\package_manager\Build

Code

protected function createVendorRepository(array $versions = []) : void {
    $packages = [];
    $class_loaders = ClassLoader::getRegisteredLoaders();
    $workspace_dir = $this->getWorkspaceDirectory();
    $finder = Finder::create()->in([
        $this->getWorkspaceDrupalRoot() . '/core',
        "{$workspace_dir}/composer/Metapackage",
        "{$workspace_dir}/composer/Plugin",
        key($class_loaders),
    ])
        ->depth('< 3')
        ->files()
        ->name('composer.json');
    
    /** @var \Symfony\Component\Finder\SplFileInfo $file */
    foreach ($finder as $file) {
        $package_info = json_decode($file->getContents(), TRUE, flags: JSON_THROW_ON_ERROR);
        $name = $package_info['name'];
        $requirements = $package_info['require'] ?? [];
        // These polyfills are dependencies of some packages, but for reasons we
        // don't understand, they are not installed in code bases built on PHP
        // versions that are newer than the ones being polyfilled, which means we
        // won't be able to build our test project because these polyfills aren't
        // available in the local code base. Since we're guaranteed to be on PHP
        // 8.3 or later, no package should need to polyfill older versions.
        unset($requirements['symfony/polyfill-php72'], $requirements['symfony/polyfill-php73'], $requirements['symfony/polyfill-php74'], $requirements['symfony/polyfill-php80'], $requirements['symfony/polyfill-php81'], $requirements['symfony/polyfill-php82'], $requirements['symfony/polyfill-php83']);
        // If this package requires any Drupal core packages, ensure it allows
        // any version.
        self::unboundCoreConstraints($requirements);
        // In certain situations, like Drupal CI, auto_updates might be
        // required into the code base by Composer. This may cause it to be added to
        // the drupal/core-recommended metapackage, which can prevent the test site
        // from being built correctly, among other deleterious effects. To prevent
        // such shenanigans, always remove drupal/auto_updates from
        // drupal/core-recommended.
        if ($name === 'drupal/core-recommended') {
            unset($requirements['drupal/auto_updates']);
        }
        try {
            $version = $versions[$name] ?? $package_info['version'] ?? InstalledVersions::getPrettyVersion($name);
        } catch (\OutOfBoundsException) {
            $version = 'dev-main';
        }
        // Create a pared-down package definition that has just enough information
        // for Composer to install the package from the local copy: the name,
        // version, package type, source path ("dist" in Composer terminology),
        // and the autoload information, so that the classes provided by the
        // package will actually be loadable in the test site we're building.
        $path = $file->getPath();
        $packages[$name][$version] = [
            'name' => $name,
            'version' => $version,
            'type' => $package_info['type'] ?? 'library',
            // Disabling symlinks in the transport options doesn't seem to have an
            // effect, so we use the COMPOSER_MIRROR_PATH_REPOS environment
            // variable to force mirroring in ::createTestProject().
'dist' => [
                'type' => 'path',
                'url' => $path,
            ],
            'require' => $requirements,
            'autoload' => $package_info['autoload'] ?? [],
            'provide' => $package_info['provide'] ?? [],
            // Composer plugins are loaded and activated as early as possible, and
            // they must have a `class` key defined in their `extra` section, along
            // with a dependency on `composer-plugin-api` (plus any other real
            // runtime dependencies). This is also necessary for packages that ship
            // scaffold files, like Drupal core.
'extra' => $package_info['extra'] ?? [],
        ];
    }
    $data = json_encode([
        'packages' => $packages,
    ], JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT);
    file_put_contents($workspace_dir . '/vendor.json', $data);
}

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.