devel_wizard-2.x-dev/src/Plugin/DevelWizard/Spell/ProjectDrupalDrushSpell.php

src/Plugin/DevelWizard/Spell/ProjectDrupalDrushSpell.php
<?php

declare(strict_types=1);

namespace Drupal\devel_wizard\Plugin\DevelWizard\Spell;

use Drupal\Component\Plugin\ConfigurableInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Plugin\PluginFormInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\Core\StringTranslation\TranslationInterface;
use Drupal\Core\Template\TwigEnvironment;
use Drupal\devel_wizard\Attribute\DevelWizardSpell;
use Drupal\devel_wizard\ShellProcessFactoryInterface;
use Drupal\devel_wizard\Utils;
use Psr\Log\LoggerInterface;
use Sweetchuck\Utils\VersionNumber;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Filesystem\Path;
use Symfony\Component\String\UnicodeString;

#[DevelWizardSpell(
  id: 'devel_wizard_project_drupal_drush',
  category: new TranslatableMarkup('Project'),
  label: new TranslatableMarkup('Project - drupal-drush'),
  description: new TranslatableMarkup('Creates a new "drupal/foo" package with type "drupal-drush".'),
  tags: [
    'code' => new TranslatableMarkup('Code'),
    'project' => new TranslatableMarkup('Project'),
    'drush' => new TranslatableMarkup('Drush'),
  ],
)]
class ProjectDrupalDrushSpell extends SpellBase implements
  PluginFormInterface,
  ConfigurableInterface,
  ContainerFactoryPluginInterface {

  public const ERROR_CODE_GIT_INIT = 1;

  protected ShellProcessFactoryInterface $processFactory;

  protected Filesystem $fs;

  protected TwigEnvironment $twig;

  public static function create(
    ContainerInterface $container,
    array $configuration,
    $plugin_id,
    $plugin_definition,
  ) {
    return new static(
      $configuration,
      $plugin_id,
      $plugin_definition,
      $container->get('messenger'),
      $container->get('logger.channel.devel_wizard_spell'),
      $container->get('string_translation'),
      $container->get('devel_wizard.utils'),
      $container->get('config.factory'),
      $container->get('twig'),
      $container->get('devel_wizard.shell_process_factory'),
      new Filesystem(),
    );
  }

  /**
   * {@inheritdoc}
   */
  public function __construct(
    array $configuration,
    $plugin_id,
    $plugin_definition,
    MessengerInterface $messenger,
    LoggerInterface $logger,
    TranslationInterface $stringTranslation,
    Utils $utils,
    ConfigFactoryInterface $configFactory,
    TwigEnvironment $twig,
    ShellProcessFactoryInterface $processFactory,
    Filesystem $fs,
  ) {
    $this->twig = $twig;
    $this->processFactory = $processFactory;
    $this->fs = $fs;
    parent::__construct(
      $configuration,
      $plugin_id,
      $plugin_definition,
      $messenger,
      $logger,
      $stringTranslation,
      $utils,
      $configFactory,
    );
  }

  /**
   * {@inheritdoc}
   */
  public function defaultConfiguration() {
    $coreVersionParts = explode('.', \Drupal::VERSION);

    return [
      'type' => 'custom',
      'machine_name' => '',
      'description' => '',
      'php_min' => '8.1',
      'core_compatibility' => [
        '10' => $coreVersionParts[0] === '10',
        '11' => $coreVersionParts[0] === '11',
        '12' => $coreVersionParts[0] === '12',
      ],

      'parent_dir' => '',

      // @todo Prefix all the Git related configs with "git_".
      'git_template' => 'default',
      'initial_git_branch' => '1.x',
      'add_git_branch_as_dir_suffix' => TRUE,

      'phpstorm_idea_enabled' => FALSE,
      'phpstorm_idea_' => [
        'project_root' => '',
        'project_name' => [],
        'version_major' => 1,
      ],
    ];
  }

  public function populateCalculatedConfigurationValues(): static {
    parent::populateCalculatedConfigurationValues();
    $conf =& $this->configuration;

    if (empty($conf['type'])) {
      throw new \InvalidArgumentException('type is required');
    }

    if (empty($conf['machine_name'])) {
      throw new \InvalidArgumentException('machine_name is required');
    }

    if (!$conf['parent_dir']) {
      $conf['parent_dir'] = match($this->configuration['type']) {
        'custom' => $this->getDefaultParentDirCustom(),
        'standalone' => $this->getDefaultParentDirStandalone(),
      };
    }

    $dirName = $conf['machine_name'];
    if ($conf['type'] === 'standalone'
      && $conf['add_git_branch_as_dir_suffix']
      && !empty($conf['initial_git_branch'])
    ) {
      $dirName .= "-{$conf['initial_git_branch']}";
    }
    $conf['dst_dir'] = Path::join($conf['parent_dir'], $dirName);

    $version = VersionNumber::createFromString($conf['initial_git_branch']);

    $conf['phpstorm_idea']['project_root'] = $conf['dst_dir'];
    $conf['phpstorm_idea']['project_name'] = rtrim("drupal.{$conf['machine_name']}-{$version->major}", '-');

    $conf['projectType'] = 'drupal-drush';
    $conf['machineNameDash'] = str_replace('_', '-', $conf['machine_name']);
    $conf['machineNameUpperCamel'] = (new UnicodeString("a_{$conf['machine_name']}"))
      ->camel()
      ->trimPrefix('a')
      ->toString();

    return $this;
  }

  public function getDefaultParentDirCustom(): string {
    return '../drush/Commands/custom';
  }

  public function getDefaultParentDirStandalone(): string {
    // @todo Configurable standalone "drupal/*" projects directory.
    return '../../../drupal';
  }

  /**
   * {@inheritdoc}
   */
  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
    $parents = $form['#parents'];
    $configuration = $this->getConfiguration();

    $typeName = $this->utils->inputName($parents, 'type');
    $statesTypeStandalone = [
      'visible' => [
        ":input[name=\"$typeName\"]" => ['value' => 'standalone'],
      ],
    ];

    $form['type'] = [
      '#type' => 'radios',
      '#required' => TRUE,
      '#title' => $this->t('Type'),
      '#options' => [
        'custom' => $this->t('Custom'),
        'standalone' => $this->t('Standalone'),
      ],
      '#default_value' => $configuration['type'],
    ];

    $form['machine_name'] = [
      '#type' => 'textfield',
      '#pattern' => '[a-z][a-z0-9_]{3,32}',
      '#required' => TRUE,
      '#title' => $this->t('Machine-name'),
      '#description' => $this->t('Machine readable name of the new project'),
      '#default_value' => $configuration['machine_name'],
    ];

    $form['description'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Description'),
      '#default_value' => $configuration['description'],
    ];

    $form['php_min'] = [
      '#type' => 'select',
      '#title' => $this->t('Minimum PHP version'),
      '#options' => $this->utils->phpVersionChoices(),
      '#default_value' => $configuration['php_min'],
      '#states' => $statesTypeStandalone,
    ];

    $form['core_compatibility'] = [
      '#type' => 'checkboxes',
      '#title' => $this->t('drupal/core-recommended compatibility'),
      '#description' => $this->t(
        'Value for <code>@json_ref</code>',
        [
          '@json_ref' => '*.info.yml#/core_compatibility',
        ],
      ),
      '#options' => [
        '10' => '10',
        '11' => '11',
        '12' => '12',
      ],
      '#default_value' => array_keys($configuration['core_compatibility'], TRUE, TRUE),
      '#states' => $statesTypeStandalone,
    ];

    $form['parent_dir'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Parent directory'),
      '#field_suffix' => '<code>/&lt;machine_name&gt;/&lt;machine_name&gt;.info.yml</code>',
      '#default_value' => $configuration['parent_dir'],
      '#description' => $this->t(
        <<< 'TEXT'
        Leave this empty to use the default value based on the type:
        <ul>
          <li>Sub-module: <code>@dir_submodule</code></li>
          <li>Standalone: <code>@dir_standalone</code></li>
        </ul>
        TEXT,
        [
          '@dir_submodule' => $this->getDefaultParentDirCustom(),
          '@dir_standalone' => $this->getDefaultParentDirStandalone(),
        ],
      ),
    ];

    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
    // @todo Implement validateConfigurationForm() method.
  }

  /**
   * {@inheritdoc}
   */
  public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
    $values = $form_state->getValue($form['#parents'], []);
    $values['core_compatibility'] = array_fill_keys(
      array_keys($values['core_compatibility'], TRUE),
      TRUE,
    );
    $this->setConfiguration($values);
  }

  /**
   * @throws \Twig\Error\Error
   */
  protected function doIt(): static {
    $this
      ->doItDeployFiles()
      ->doItGit()
      ->doItPhpstorm();

    drupal_flush_all_caches();

    $this->batchContext['finished'] = 1.0;

    return $this;
  }

  /**
   * @throws \Twig\Error\Error
   */
  protected function doItDeployFiles(): static {
    $conf =& $this->configuration;

    $files = [];

    $files[Path::join($conf['dst_dir'], 'README.md')] = $this->getReadmeMdContent();
    $files[Path::join($conf['dst_dir'], 'Commands', 'drush.yml')] = '{}';

    if ($conf['type'] === 'standalone') {
      $files[Path::join($conf['dst_dir'], 'composer.json')] = json_encode(
        $this->getComposerJsonData(),
        $this->utils->getJsonEncodeFlags(),
      ) . "\n";

      $files[Path::join($conf['dst_dir'], '.editorconfig')] = $this->getEditorConfigContent();
      $files[Path::join($conf['dst_dir'], '.gitignore')] = $this->getGitIgnoreContent();
      $files[Path::join($conf['dst_dir'], 'phpcs.xml.dist')] = $this->getPhpcsXmlDistContent();
      $files += $this->getPhpunitContents();
      $files += $this->getPhpStanContents();
      $files += $this->getRoboContents();

      // @todo If not standalone and there is already PHPStan, PHPCS or PHPUnit
      // configuration then maybe those are have to be adjusted.
    }

    $this->fs->mkdir(Path::join($conf['dst_dir'], 'Commands', $conf['machine_name']));
    foreach ($files as $filePath => $fileContent) {
      $this->fs->mkdir(Path::getDirectory($filePath));
      $this->fs->dumpFile($filePath, $fileContent);
      $this->messageFilesystemEntryCreate($filePath);
    }

    // PHPMD config.
    // GitHubActions.
    // CircleCI.
    // GitLab.
    // Jenkins.
    return $this;
  }

  protected function doItGit(): static {
    $conf =& $this->configuration;

    $gitDir = Path::join(
      $conf['dst_dir'],
      '.git',
    );

    if ($this->fs->exists($gitDir)) {
      $this->logger->info(
        'git dir already exists: @git_dir',
        [
          '@git_dir' => $gitDir,
        ],
      );

      return $this;
    }

    $command = [
      'git',
      'init',
    ];

    if ($conf['git_template']) {
      $command[] = "--template={$conf['git_template']}";
    }

    if (!empty($conf['initial_git_branch'])) {
      $command[] = "--initial-branch={$conf['initial_git_branch']}";
    }

    // @todo Remove \getenv().
    $process = $this
      ->processFactory
      ->createInstance($command, $conf['dst_dir'], getenv());
    $process->run();

    if ($process->getExitCode() === 0) {
      return $this;
    }

    // @todo Logger, messenger.
    throw new \RuntimeException(
      $process->getErrorOutput(),
      static::ERROR_CODE_GIT_INIT,
    );
  }

  /**
   * @throws \Twig\Error\Error
   *
   * @todo Use devel_wizard_phpstorm_idea spell.
   */
  protected function doItPhpstorm(): static {
    $conf =& $this->configuration;
    if (!$conf['phpstorm_idea_enabled']) {
      return $this;
    }

    foreach ($this->getPhpstormContents() as $filePath => $fileContent) {
      $this->fs->mkdir(Path::getDirectory($filePath));
      $this->fs->dumpFile($filePath, $fileContent);
      $this->messageFilesystemEntryCreate($filePath);
    }

    return $this;
  }

  /**
   * @return array<string, string>
   *
   * @throws \Twig\Error\Error
   */
  protected function getPhpstormContents(): array {
    $conf =& $this->configuration;
    $dstDir = Path::join($conf['dst_dir'], '.idea');

    return [
      "$dstDir/.name" => $conf['phpstorm_idea']['project_name'],
      "$dstDir/inspectionProfiles/Project_Default.xml" => $this->twig->render(
        '@devel_wizard/project-drupal-drush/idea/inspectionProfiles/Project_Default.xml.twig',
        $conf,
      ),
      "$dstDir/{$conf['phpstorm_idea']['project_name']}.iml" => $this->twig->render(
        '@devel_wizard/project-drupal-drush/idea/PROJECT_NAME.iml.twig',
        $conf,
      ),
      "$dstDir/modules.xml" => $this->twig->render(
        '@devel_wizard/project-drupal-drush/idea/modules.xml.twig',
        $conf,
      ),
      "$dstDir/php.xml" => $this->twig->render(
        '@devel_wizard/project-drupal-drush/idea/php.xml.twig',
        $conf,
      ),
      "$dstDir/phpunit.xml" => $this->twig->render(
        '@devel_wizard/project-drupal-drush/idea/phpunit.xml.twig',
        $conf,
      ),
      "$dstDir/vcs.xml" => $this->twig->render(
        '@devel_wizard/project-drupal-drush/idea/vcs.xml.twig',
        $conf,
      ),
      "$dstDir/workspace.xml" => $this->twig->render(
        '@devel_wizard/project-drupal-drush/idea/workspace.xml.twig',
        $conf,
      ),
    ];
  }

  protected function getReadmeMdContent(): string {
    return implode(
      "\n",
      [
        "# drupal/{$this->configuration['machine_name']}",
        '',
        '@todo',
        '',
      ],
    );
  }

  protected function getComposerJsonData(): array {
    $conf =& $this->configuration;

    return [
      'type' => 'drupal-drush',
      'name' => "drupal/{$conf['machine_name']}",
      'description' => $conf['description'] ?? '',
      'license' => 'GPL-3.0-or-later',
      'keywords' => [
        'drupal',
        'drush',
      ],
      'homepage' => "https://drupal.org/project/{$conf['machine_name']}",
      'support' => [
        'issues' => "https://www.drupal.org/project/issues/{$conf['machine_name']}",
        'source' => "https://git.drupalcode.org/project/{$conf['machine_name']}",
      ],
      'minimum-stability' => 'dev',
      'prefer-stable' => TRUE,
      'config' => [
        'allow-plugins' => [
          'composer/installers' => TRUE,
          'cweagans/composer-patches' => TRUE,
          'dealerdirect/phpcodesniffer-composer-installer' => TRUE,
          'drupal/core-composer-scaffold' => TRUE,
          'oomphinc/composer-installers-extender' => TRUE,
        ],
        'optimize-autoloader' => TRUE,
        'preferred-install' => [
          '*' => 'dist',
        ],
        'sort-packages' => TRUE,
      ],
      'require' => [
        'php' => ">={$conf['php_min']}",
      ],
      'require-dev' => [
        'ext-pdo' => '*',
        'ext-pdo_sqlite' => '*',
        'behat/mink' => '^1.10',
        'behat/mink-browserkit-driver' => '^2.1',
        'composer/installers' => '^1.6',
        'cweagans/composer-patches' => '^2.0',
        'dealerdirect/phpcodesniffer-composer-installer' => '^1.0',
        'drupal/core-composer-scaffold' => '^10.0',
        'drupal/core-recommended' => '^10.0',
        'drush/drush' => '^12.1',
        'mikey179/vfsstream' => '^1.6',
        'nuvoleweb/robo-config' => '^3.0',
        'oomphinc/composer-installers-extender' => '^2.0',
        'phpmd/phpmd' => '^2.13',
        'phpspec/prophecy-phpunit' => '^2.0',
        'phpunit/phpunit' => '^9.0',
        'sweetchuck/robo-phpcs' => '3.x-dev',
        'sweetchuck/robo-phpmd' => '3.x-dev',
        'sweetchuck/robo-phpstan' => '2.x-dev',
        'sweetchuck/utils' => '1.x-dev',
        'symfony/browser-kit' => '^6.3',
        'symfony/phpunit-bridge' => '^6.3',
        'weitzman/drupal-test-traits' => '^2.1',
      ],
      'suggest' => [
        'drush/drush' => '^12.0',
      ],
      'autoload' => [
        'psr-4' => [
          "Drush\\Commands\\{$conf['machine_name']}\\" => "Commands/{$conf['machine_name']}/",
          "Drupal\\{$conf['machine_name']}\\" => 'src/',
        ],
      ],
      'autoload-dev' => [
        'psr-4' => [
          "Drupal\\Tests\\{$conf['machine_name']}\\" => 'tests/src/',

          'Drupal\\Tests\\' => 'tests/fixtures/repository/d9/project_01/docroot/core/tests/Drupal/Tests/',
          'Drupal\\TestTools\\' => 'tests/fixtures/repository/d9/project_01/docroot/core/tests/Drupal/TestTools/',
          'Drupal\\KernelTests\\' => 'tests/fixtures/repository/d9/project_01/docroot/core/tests/Drupal/KernelTests/',
        ],
      ],
      'extra' => [
        'drush' => [
          'services' => [
            'drush.services.yml' => '*',
          ],
        ],
        'installer-types' => [
          'bower-asset',
          'npm-asset',
        ],
        'installer-paths' => [
          'tests/fixtures/repository/d9/project_01/docroot/core' => [
            'type:drupal-core',
          ],
          'tests/fixtures/repository/d9/project_01/docroot/libraries/{$name}' => [
            'type:bower-asset',
            'type:npm-asset',
            'type:drupal-library',
          ],
          'tests/fixtures/repository/d9/project_01/docroot/modules/contrib/{$name}' => [
            'type:drupal-module',
          ],
          'tests/fixtures/repository/d9/project_01/docroot/profiles/contrib/{$name}' => [
            'type:drupal-profile',
          ],
          'tests/fixtures/repository/d9/project_01/docroot/themes/contrib/{$name}' => [
            'type:drupal-theme',
          ],
          'tests/fixtures/repository/d9/project_01/drush/Commands/contrib/{$name}' => [
            'type:drupal-drush',
          ],
        ],
        'drupal-scaffold' => [
          'locations' => [
            'web-root' => 'tests/fixtures/repository/d9/project_01/docroot',
          ],
          'file-mapping' => [
            '[web-root]/modules/.gitignore' => [
              'mode' => 'skip',
            ],
            '[web-root]/modules/README.txt' => [
              'mode' => 'skip',
            ],
            '[web-root]/profiles/.gitignore' => [
              'mode' => 'skip',
            ],
            '[web-root]/profiles/README.txt' => [
              'mode' => 'skip',
            ],
            '[web-root]/themes/.gitignore' => [
              'mode' => 'skip',
            ],
            '[web-root]/themes/README.txt' => [
              'mode' => 'skip',
            ],
            '[web-root]/sites/example.settings.local.php' => [
              'mode' => 'skip',
            ],
            '[web-root]/sites/.gitignore' => [
              'mode' => 'skip',
            ],
            '[web-root]/sites/README.txt' => [
              'mode' => 'skip',
            ],
            '[web-root]/.csslintrc' => [
              'mode' => 'skip',
            ],
            '[web-root]/.editorconfig' => [
              'mode' => 'skip',
            ],
            '[web-root]/.eslintignore' => [
              'mode' => 'skip',
            ],
            '[web-root]/.eslintrc.json' => [
              'mode' => 'skip',
            ],
            '[web-root]/.gitattributes' => [
              'mode' => 'skip',
            ],
            '[web-root]/.gitignore' => [
              'mode' => 'skip',
            ],
            '[web-root]/example.gitignore' => [
              'mode' => 'skip',
            ],
            '[web-root]/INSTALL.txt' => [
              'mode' => 'skip',
            ],
            '[web-root]/README.txt' => [
              'mode' => 'skip',
            ],
            '[web-root]/.htaccess' => [
              'mode' => 'skip',
            ],
            '[web-root]/web.config' => [
              'mode' => 'skip',
            ],
            '[project-root]/.editorconfig' => [
              'mode' => 'skip',
            ],
          ],
          'initial' => [
            'sites/default/default.services.yml' => 'sites/default/services.yml',
            'sites/default/default.settings.php' => 'sites/default/settings.php',
          ],
        ],
        $conf['machine_name'] => [
          'fixtures' => [
            'filesToSymlink' => [],
          ],
        ],
      ],
      'scripts' => [
        'post-install-cmd' => [
          '@prepare',
        ],
        'post-update-cmd' => [],
        'clean' => [
          '@clean:reports',
          '@clean:composer',
        ],
        'clean:reports' => [
          '[ ! -d ./reports/ ] || find ./reports/ -mindepth 1 -maxdepth 1 -exec rm --recursive --force {} \;',
        ],
        'clean:composer' => [
          'rm --recursive --force ./vendor/',
          'chmod --recursive u+w tests/',
          'git clean --force -d -x -- ./tests/',
          'git clean --force -d -X -- ./tests/',
        ],
        'prepare' => [
          '@prepare:phpunit-xml',
          '@prepare:repository',
          '@prepare:project',
        ],
        'prepare:phpunit-xml' => [
          "\\Drupal\\Tests\\{$conf['machine_name']}\\Helper\\ComposerScripts::cmdPreparePhpunitXml",
        ],
        'prepare:repository' => [
          "\\Drupal\\Tests\\{$conf['machine_name']}\\Helper\\ComposerScripts::cmdPrepareRepository",
        ],
        'prepare:project' => [
          "\\Drupal\\Tests\\{$conf['machine_name']}\\Helper\\ComposerScripts::cmdPrepareProject",
        ],
        'lint' => [
          '@lint:phpcs',
        ],
        'lint:phpcs' => [
          'phpcs',
        ],
        'test' => [
          '@clean:reports',
          '@test:unit',
          '@test:integration',
        ],
        'test:unit' => [
          'mkdir -p ./reports/machine/coverage-php/',
          implode(' ', [
            'phpunit',
            '--testsuite="Unit"',
            '--coverage-html ./reports/human/coverage/Unit/html',
            '--testdox-html ./reports/human/testdox/Unit.html',
            '--coverage-clover ./reports/machine/coverage-clover/Unit.xml',
            '--coverage-php ./reports/machine/coverage-php/Unit.php',
            '--log-junit ./reports/machine/junit/Unit.xml',
          ]),
        ],
        'test:integration' => [
          'mkdir -p ./reports/machine/coverage-php/',
          implode(' ', [
            'phpunit',
            '--testsuite="Integration"',
            '--coverage-html ./reports/human/coverage/Integration/html',
            '--testdox-html ./reports/human/testdox/Integration.html',
            '--coverage-clover ./reports/machine/coverage-clover/Integration.xml',
            '--coverage-php ./reports/machine/coverage-php/Integration.php',
            '--log-junit ./reports/machine/junit/Integration.xml',
          ]),
        ],
      ],
      'scripts-descriptions' => [
        'clean' => 'Clean third-party codes and generated reports.',
      ],
    ];
  }

  /**
   * @throws \Twig\Error\Error
   */
  protected function getEditorConfigContent(): string {
    return $this->twig->render(
      '@devel_wizard/project/editorconfig.twig',
      $this->getConfiguration(),
    );
  }

  /**
   * @throws \Twig\Error\Error
   */
  protected function getGitIgnoreContent(): string {
    return $this->twig->render(
      '@devel_wizard/project/gitignore.twig',
      $this->getConfiguration(),
    );
  }

  /**
   * @throws \Twig\Error\Error
   */
  protected function getPhpcsXmlDistContent(): string {
    return $this->twig->render(
      '@devel_wizard/project-drupal-drush/phpcs.xml.dist.twig',
      $this->getConfiguration(),
    );
  }

  /**
   * @return array<string, string>
   *
   * @throws \Twig\Error\Error
   */
  protected function getPhpStanContents(): array {
    $conf =& $this->configuration;
    $dstDir = $conf['dst_dir'];

    return [
      "$dstDir/phpstan.dist.neon" => $this->twig->render(
        '@devel_wizard/project/phpstan.dist.neon.twig',
        $conf,
      ),
      "$dstDir/.phpstan/parameters.general.neon" => $this->twig->render(
        '@devel_wizard/project/phpstan/parameters.general.neon.twig',
        $conf,
      ),
      "$dstDir/.phpstan/parameters.ignoreErrors.neon" => $this->twig->render(
        '@devel_wizard/project/phpstan/parameters.ignoreErrors.neon.twig',
        $conf,
      ),
      "$dstDir/.phpstan/parameters.paths.neon" => $this->twig->render(
        '@devel_wizard/project/phpstan/parameters.paths.neon.twig',
        $conf,
      ),
      "$dstDir/.phpstan/parameters.typeAliases.dev.neon" => $this->twig->render(
        '@devel_wizard/project/phpstan/parameters.typeAliases.dev.neon.twig',
        $conf,
      ),
      "$dstDir/.phpstan/parameters.typeAliases.prod.neon" => $this->twig->render(
        '@devel_wizard/project/phpstan/parameters.typeAliases.prod.neon.twig',
        $conf,
      ),
    ];
  }

  /**
   * @return array<string, string>
   *
   * @throws \Twig\Error\Error
   */
  protected function getRoboContents(): array {
    $dstDir = $this->configuration['dst_dir'];

    return [
      "$dstDir/RoboFile.php" => $this->twig->render(
        '@devel_wizard/project-drupal-drush/RoboFile.php.twig',
        $this->configuration,
      ),
      "$dstDir/robo.yml.dist" => $this->twig->render(
        '@devel_wizard/project/robo.yml.dist.twig',
        $this->configuration,
      ),
    ];
  }

  /**
   * @return array<string, string>
   *
   * @throws \Twig\Error\Error
   */
  protected function getPhpunitContents(): array {
    $dstDir = $this->configuration['dst_dir'];

    return [
      "$dstDir/phpunit.xml.dist" => $this->twig->render(
        '@devel_wizard/project-drupal-drush/phpunit.xml.dist.twig',
        $this->configuration,
      ),
      "$dstDir/tests/src/bootstrap.php" => $this->twig->render(
        '@devel_wizard/project-drupal-drush/tests/src/bootstrap.php.twig',
        $this->configuration,
      ),
      "$dstDir/tests/src/Helper/ComposerScripts.php" => $this->twig->render(
        '@devel_wizard/project-drupal-drush/tests/src/Helper/ComposerScripts.php.twig',
        $this->configuration,
      ),
    ];

  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc