You are here

public function ComposerProjectTemplatesTest::testTemplateCreateProject in Drupal 8

Same name and namespace in other branches
  1. 9 core/tests/Drupal/BuildTests/Composer/Template/ComposerProjectTemplatesTest.php \Drupal\BuildTests\Composer\Template\ComposerProjectTemplatesTest::testTemplateCreateProject()

@dataProvider provideTemplateCreateProject

File

core/tests/Drupal/BuildTests/Composer/Template/ComposerProjectTemplatesTest.php, line 106

Class

ComposerProjectTemplatesTest
Demonstrate that Composer project templates are buildable as patched.

Namespace

Drupal\BuildTests\Composer\Template

Code

public function testTemplateCreateProject($project, $package_dir, $docroot_dir) {
  $composer_version_line = exec('composer --version');
  if (strpos($composer_version_line, 'Composer version 2') !== FALSE) {

    // @todo Remove in https://www.drupal.org/project/drupal/issues/3128631
    $this
      ->markTestSkipped("Composer 2 not supported for this test yet.");
  }

  // Make a working COMPOSER_HOME directory for setting global composer config
  $composer_home = $this
    ->getWorkspaceDirectory() . '/composer-home';
  mkdir($composer_home);

  // Disable packagist globally (but only in our own custom COMPOSER_HOME).
  // It is necessary to do this globally rather than in our SUT composer.json
  // in order to ensure that Packagist is disabled during the
  // `composer create-project` command.
  $this
    ->executeCommand("COMPOSER_HOME={$composer_home} composer config --no-interaction --global repo.packagist false");
  $this
    ->assertCommandSuccessful();

  // Get the Drupal core version branch. For instance, this should be
  // 8.9.x-dev for the 8.9.x branch.
  $core_version = Composer::drupalVersionBranch();

  // Create a "Composer"-type repository containing one entry for every
  // package in the vendor directory.
  $vendor_packages_path = $this
    ->getWorkspaceDirectory() . '/vendor_packages/packages.json';
  $this
    ->makeVendorPackage($vendor_packages_path);

  // Make a copy of the code to alter.
  $this
    ->copyCodebase();

  // Remove the packages.drupal.org entry (and any other custom repository)
  // from the SUT's repositories section. There is no way to do this via
  // `composer config --unset`, so we read and rewrite composer.json.
  $composer_json_path = $this
    ->getWorkspaceDirectory() . "/{$package_dir}/composer.json";
  $composer_json = json_decode(file_get_contents($composer_json_path), TRUE);
  unset($composer_json['repositories']);
  $json = json_encode($composer_json, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
  file_put_contents($composer_json_path, $json);

  // Set up the template to use our path repos. Inclusion of metapackages is
  // reported differently, so we load up a separate set for them.
  $metapackage_path_repos = $this
    ->getPathReposForType($this
    ->getWorkspaceDirectory(), 'Metapackage');
  $path_repos = array_merge($metapackage_path_repos, $this
    ->getPathReposForType($this
    ->getWorkspaceDirectory(), 'Plugin'));

  // Always add drupal/core as a path repo.
  $path_repos['drupal/core'] = $this
    ->getWorkspaceDirectory() . '/core';
  foreach ($path_repos as $name => $path) {
    $this
      ->executeCommand("composer config --no-interaction repositories.{$name} path {$path}", $package_dir);
    $this
      ->assertCommandSuccessful();
  }
  $this
    ->executeCommand("composer config --no-interaction repositories.local composer file://" . $vendor_packages_path, $package_dir);
  $this
    ->assertCommandSuccessful();
  $repository_path = $this
    ->getWorkspaceDirectory() . '/test_repository/packages.json';
  $this
    ->makeTestPackage($repository_path, $core_version);
  $autoloader = $this
    ->getWorkspaceDirectory() . '/testproject' . $docroot_dir . '/autoload.php';
  $this
    ->assertFileNotExists($autoloader);
  $this
    ->executeCommand("COMPOSER_HOME={$composer_home} COMPOSER_ROOT_VERSION={$core_version} composer create-project --no-ansi {$project} testproject {$core_version} -s dev -vv --repository {$repository_path}");
  $this
    ->assertCommandSuccessful();

  // Ensure we used the project from our codebase.
  $this
    ->assertErrorOutputContains("Installing {$project} ({$core_version}): Symlinking from {$package_dir}");

  // Ensure that we used drupal/core from our codebase. This probably means
  // that drupal/core-recommended was added successfully by the project.
  $this
    ->assertErrorOutputContains("Installing drupal/core ({$core_version}): Symlinking from");

  // Verify that there is an autoloader. This is written by the scaffold
  // plugin, so its existence assures us that scaffolding happened.
  $this
    ->assertFileExists($autoloader);

  // In order to verify that Composer used the path repos for our project, we
  // have to get the requirements from the project composer.json so we can
  // reconcile our expectations.
  $template_json_file = $this
    ->getWorkspaceDirectory() . '/' . $package_dir . '/composer.json';
  $this
    ->assertFileExists($template_json_file);
  $json_file = new JsonFile($template_json_file);
  $template_json = $json_file
    ->read();

  // Get the require and require-dev information, and ensure that our
  // requirements are not erroneously empty.
  $this
    ->assertNotEmpty($require = array_merge($template_json['require'] ?? [], $template_json['require-dev'] ?? []));

  // Verify that path repo packages were installed.
  $path_repos = array_keys($path_repos);
  foreach (array_keys($require) as $package_name) {
    if (in_array($package_name, $path_repos)) {

      // Metapackages do not report that they were installed as symlinks, but
      // we still must check that their installed version matches
      // COMPOSER_CORE_VERSION.
      if (array_key_exists($package_name, $metapackage_path_repos)) {
        $this
          ->assertErrorOutputContains("Installing {$package_name} ({$core_version})");
      }
      else {
        $this
          ->assertErrorOutputContains("Installing {$package_name} ({$core_version}): Symlinking from");
      }
    }
  }
}