comparison vendor/chi-teck/drupal-code-generator/src/Command/Drupal_8/Project.php @ 5:12f9dff5fda9 tip

Update to Drupal core 8.7.1
author Chris Cannam
date Thu, 09 May 2019 15:34:47 +0100
parents
children
comparison
equal deleted inserted replaced
4:a9cd425dd02b 5:12f9dff5fda9
1 <?php
2
3 namespace DrupalCodeGenerator\Command\Drupal_8;
4
5 use DrupalCodeGenerator\Command\BaseGenerator;
6 use DrupalCodeGenerator\Utils;
7 use Symfony\Component\Console\Input\InputInterface;
8 use Symfony\Component\Console\Output\OutputInterface;
9 use Symfony\Component\Console\Question\ConfirmationQuestion;
10 use Symfony\Component\Console\Question\Question;
11
12 /**
13 * Implements d8:composer command.
14 *
15 * Inspired by drupal-composer/drupal-project.
16 */
17 class Project extends BaseGenerator {
18
19 protected $name = 'd8:project';
20 protected $description = 'Generates a composer project';
21 protected $alias = 'project';
22
23 const DRUPAL_DEFAULT_VERSION = '~8.6.0';
24
25 /**
26 * {@inheritdoc}
27 */
28 protected function interact(InputInterface $input, OutputInterface $output) {
29
30 $name_validator = function ($value) {
31 if (!preg_match('#[^/]+/[^/]+$#i', $value)) {
32 throw new \UnexpectedValueException('The value is not correct project name.');
33 }
34 return $value;
35 };
36 $questions['name'] = new Question('Project name (vendor/name)', FALSE);
37 $questions['name']->setValidator($name_validator);
38
39 $questions['description'] = new Question('Description');
40
41 $questions['license'] = new Question('License', 'GPL-2.0-or-later');
42 // @see https://getcomposer.org/doc/04-schema.md#license
43 $licenses = [
44 'Apache-2.0',
45 'BSD-2-Clause',
46 'BSD-3-Clause',
47 'BSD-4-Clause',
48 'GPL-2.0-only',
49 'GPL-2.0-or-later',
50 'GPL-3.0-only',
51 'GPL-3.0-or-later',
52 'LGPL-2.1-onl',
53 'LGPL-2.1-or-later',
54 'LGPL-3.0-only',
55 'LGPL-3.0-or-later',
56 'MIT',
57 'proprietary',
58 ];
59 $questions['license']->setAutocompleterValues($licenses);
60
61 // Suggest most typical document roots.
62 $document_roots = [
63 'docroot',
64 'web',
65 'www',
66 'public_html',
67 'public',
68 'htdocs',
69 'httpdocs',
70 'html',
71 ];
72 $questions['document_root'] = new Question('Document root directory, type single dot to use Composer root', 'docroot');
73 $questions['document_root']->setNormalizer(function ($value) {
74 return $value == '.' ? '' : $value;
75 });
76 $questions['document_root']->setAutocompleterValues($document_roots);
77
78 $questions['php'] = new Question('PHP version', '>=' . PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION);
79 $questions['drupal'] = new Question('Drupal version', self::DRUPAL_DEFAULT_VERSION);
80 $questions['drupal_core_strict'] = new ConfirmationQuestion('Would you like to get the same versions of Drupal core\'s dependencies as in Drupal core\'s composer.lock file?', FALSE);
81
82 $this->collectVars($input, $output, $questions);
83
84 $sections = ['require', 'require-dev'];
85
86 $questions['drush'] = new ConfirmationQuestion('Would you like to install Drush?', TRUE);
87 $vars = $this->collectVars($input, $output, $questions);
88 if ($vars['drush']) {
89 $questions['drush_installation'] = new Question('Drush installation (require|require-dev)', 'require');
90 $questions['drush_installation']->setValidator(Utils::getOptionsValidator($sections));
91 $questions['drush_installation']->setAutocompleterValues($sections);
92 $this->collectVars($input, $output, $questions);
93 }
94
95 $questions['drupal_console'] = new ConfirmationQuestion('Would you like to install Drupal Console?', !$vars['drush']);
96 $vars = $this->collectVars($input, $output, $questions);
97 if ($vars['drupal_console']) {
98 $questions['drupal_console_installation'] = new Question('Drupal Console installation (require|require-dev)', 'require-dev');
99 $questions['drupal_console_installation']->setValidator(Utils::getOptionsValidator($sections));
100 $questions['drupal_console_installation']->setAutocompleterValues($sections);
101 $this->collectVars($input, $output, $questions);
102 }
103
104 $questions['composer_patches'] = new ConfirmationQuestion('Would you like to install Composer patches plugin?', TRUE);
105 $questions['composer_merge'] = new ConfirmationQuestion('Would you like to install Composer merge plugin?', FALSE);
106 $questions['behat'] = new ConfirmationQuestion('Would you like to create Behat tests?', FALSE);
107 $questions['env'] = new ConfirmationQuestion('Would you like to load environment variables from .env files?', FALSE);
108 $questions['asset_packagist'] = new ConfirmationQuestion('Would you like to add asset-packagist repository?', FALSE);
109
110 $vars = &$this->collectVars($input, $output, $questions);
111
112 $vars['document_root_path'] = $vars['document_root'] ?
113 $vars['document_root'] . '/' : $vars['document_root'];
114
115 $this->addFile('composer.json')
116 ->content(self::buildComposerJson($vars));
117
118 $this->addFile('.gitignore')
119 ->template('d8/_project/gitignore.twig');
120
121 $this->addFile('phpcs.xml')
122 ->template('d8/_project/phpcs.xml.twig');
123
124 $this->addFile('scripts/composer/create_required_files.php')
125 ->template('d8/_project/scripts/composer/create_required_files.php.twig');
126
127 if ($vars['behat']) {
128 $this->addFile('tests/behat/behat.yml')
129 ->template('d8/_project/tests/behat/behat.yml.twig');
130
131 $this->addFile('tests/behat/local.behat.yml')
132 ->template('d8/_project/tests/behat/local.behat.yml.twig');
133
134 $this->addFile('tests/behat/bootstrap/BaseContext.php')
135 ->template('d8/_project/tests/behat/bootstrap/BaseContext.php.twig');
136
137 $this->addFile('tests/behat/bootstrap/ExampleContext.php')
138 ->template('d8/_project/tests/behat/bootstrap/ExampleContext.php.twig');
139
140 $this->addFile('tests/behat/features/example/user_forms.feature')
141 ->template('d8/_project/tests/behat/features/example/user_forms.feature.twig');
142 }
143
144 if ($vars['env']) {
145 $this->addFile('.env.example')
146 ->template('d8/_project/env.example.twig');
147 $this->addFile('load.environment.php')
148 ->template('d8/_project/load.environment.php.twig');
149 }
150
151 if ($vars['document_root']) {
152 $this->addDirectory('config/sync');
153 }
154
155 if ($vars['drush']) {
156 $this->addFile('drush/drush.yml')
157 ->template('d8/_project/drush/drush.yml.twig');
158 $this->addFile('drush/Commands/PolicyCommands.php')
159 ->template('d8/_project/drush/Commands/PolicyCommands.php.twig');
160 $this->addFile('drush/sites/self.site.yml')
161 ->template('d8/_project/drush/sites/self.site.yml.twig');
162 $this->addFile('scripts/sync-site.sh')
163 ->template('d8/_project/scripts/sync-site.sh.twig')
164 ->mode(0544);
165 }
166
167 $this->addFile('patches/.keep')->content('');
168 $this->addDirectory($vars['document_root_path'] . 'modules/contrib');
169 $this->addDirectory($vars['document_root_path'] . 'modules/custom');
170 $this->addDirectory($vars['document_root_path'] . 'modules/custom');
171 $this->addDirectory($vars['document_root_path'] . 'libraries');
172 }
173
174 /**
175 * {@inheritdoc}
176 */
177 protected function execute(InputInterface $input, OutputInterface $output) {
178 $result = parent::execute($input, $output);
179 if ($result === 0) {
180 $output->writeln(' <info>Next steps:</info>');
181 $output->writeln(' <info>–––––––––––</info>');
182 $output->writeln(' <info>1. Review generated files</info>');
183 $output->writeln(' <info>2. Run <comment>composer install</comment> command</info>');
184 $output->writeln(' <info>3. Install Drupal</info>');
185 $output->writeln('');
186 }
187 return $result;
188 }
189
190 /**
191 * Builds composer.json file.
192 *
193 * @param array $vars
194 * Collected variables.
195 *
196 * @return string
197 * Encoded JSON content.
198 */
199 protected static function buildComposerJson(array $vars) {
200
201 $document_root_path = $vars['document_root_path'];
202
203 $composer_json = [];
204
205 $composer_json['name'] = $vars['name'];
206 $composer_json['description'] = $vars['description'];
207 $composer_json['type'] = 'project';
208 $composer_json['license'] = $vars['license'];
209
210 $composer_json['repositories'][] = [
211 'type' => 'composer',
212 'url' => 'https://packages.drupal.org/8',
213 ];
214 if ($vars['asset_packagist']) {
215 $composer_json['repositories'][] = [
216 'type' => 'composer',
217 'url' => 'https://asset-packagist.org',
218 ];
219 }
220
221 $require = [];
222 $require_dev = [];
223
224 self::addPackage($require, 'drupal/core');
225 $require['drupal/core'] = $vars['drupal'];
226 self::addPackage($require, 'composer/installers');
227 self::addPackage($require, 'drupal-composer/drupal-scaffold');
228 self::addPackage($require, 'zaporylie/composer-drupal-optimizations');
229 $require_dev['webflo/drupal-core-require-dev'] = $vars['drupal'];
230
231 if ($vars['asset_packagist']) {
232 self::addPackage($require, 'oomphinc/composer-installers-extender');
233 }
234
235 if ($vars['drupal_core_strict']) {
236 $require['webflo/drupal-core-strict'] = $vars['drupal'];
237 }
238
239 if ($vars['drush']) {
240 $vars['drush_installation'] == 'require'
241 ? self::addPackage($require, 'drush/drush')
242 : self::addPackage($require_dev, 'drush/drush');
243 }
244
245 if ($vars['drupal_console']) {
246 $vars['drupal_console_installation'] == 'require'
247 ? self::addPackage($require, 'drupal/console')
248 : self::addPackage($require_dev, 'drupal/console');
249 }
250
251 if ($vars['composer_patches']) {
252 self::addPackage($require, 'cweagans/composer-patches');
253 }
254
255 if ($vars['composer_merge']) {
256 self::addPackage($require, 'wikimedia/composer-merge-plugin');
257 }
258
259 if ($vars['behat']) {
260 // Behat and Mink drivers are Drupal core dev dependencies.
261 self::addPackage($require_dev, 'drupal/drupal-extension');
262 }
263
264 if ($vars['env']) {
265 self::addPackage($require, 'symfony/dotenv');
266 }
267
268 $composer_json['require'] = [
269 'php' => $vars['php'],
270 'ext-curl' => '*',
271 'ext-gd' => '*',
272 'ext-json' => '*',
273 ];
274 ksort($require);
275 $composer_json['require'] += $require;
276
277 ksort($require_dev);
278 $composer_json['require-dev'] = $require_dev;
279
280 // PHPUnit is core dev dependency.
281 $composer_json['scripts']['phpunit'] = 'phpunit --colors=always --configuration ' . $document_root_path . 'core ' . $document_root_path . 'modules/custom';
282 if ($vars['behat']) {
283 $composer_json['scripts']['behat'] = 'behat --colors --config=tests/behat/local.behat.yml';
284 }
285 $composer_json['scripts']['phpcs'] = 'phpcs --standard=phpcs.xml';
286 $composer_json['scripts']['post-install-cmd'][] = '@php ./scripts/composer/create_required_files.php';
287 $composer_json['scripts']['post-update-cmd'][] = '@php ./scripts/composer/create_required_files.php';
288
289 $composer_json['minimum-stability'] = 'dev';
290 $composer_json['prefer-stable'] = TRUE;
291
292 $composer_json['config'] = [
293 'sort-packages' => TRUE,
294 'bin-dir' => 'bin',
295 ];
296
297 if ($vars['env']) {
298 $composer_json['autoload']['files'][] = 'load.environment.php';
299 }
300
301 if ($vars['composer_patches']) {
302 $composer_json['extra']['composer-exit-on-patch-failure'] = TRUE;
303 }
304
305 if ($vars['asset_packagist']) {
306 $composer_json['extra']['installer-types'] = [
307 'bower-asset',
308 'npm-asset',
309 ];
310 }
311 $composer_json['extra']['installer-paths'] = [
312 $document_root_path . 'core' => ['type:drupal-core'],
313 $document_root_path . 'libraries/{$name}' => ['type:drupal-library'],
314 $document_root_path . 'modules/contrib/{$name}' => ['type:drupal-module'],
315 $document_root_path . 'themes/{$name}' => ['type:drupal-theme'],
316 'drush/{$name}' => ['type:drupal-drush'],
317 ];
318 if ($vars['asset_packagist']) {
319 $composer_json['extra']['installer-paths'][$document_root_path . 'libraries/{$name}'][] = 'type:bower-asset';
320 $composer_json['extra']['installer-paths'][$document_root_path . 'libraries/{$name}'][] = 'type:npm-asset';
321 }
322
323 $composer_json['extra']['drupal-scaffold']['excludes'] = [
324 '.csslintrc',
325 '.editorconfig',
326 '.eslintignore',
327 '.eslintrc.json',
328 '.gitattributes',
329 '.ht.router.php',
330 '.htaccess',
331 'robots.txt',
332 'update.php',
333 'web.config',
334 ];
335 // Initial files are created but never updated.
336 $composer_json['extra']['drupal-scaffold']['initial'] = [
337 '.htaccess' => '.htaccess',
338 'robots.txt' => 'robots.txt',
339 ];
340
341 // Move these files to Composer root.
342 if ($vars['document_root']) {
343 $composer_json['extra']['drupal-scaffold']['initial']['.editorconfig'] = '../.editorconfig';
344 $composer_json['extra']['drupal-scaffold']['initial']['.gitattributes'] = '../.gitattributes';
345 }
346 ksort($composer_json['extra']['drupal-scaffold']['initial']);
347
348 if ($vars['composer_merge']) {
349 $composer_json['extra']['merge-plugin'] = [
350 'include' => [
351 $document_root_path . 'modules/custom/*/composer.json',
352 ],
353 'recurse' => TRUE,
354 ];
355 }
356
357 return json_encode($composer_json, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . "\n";
358 }
359
360 /**
361 * Requires a given package.
362 *
363 * @param array $section
364 * Section for the package (require|require-dev)
365 * @param string $package
366 * A package to be added.
367 *
368 * @todo Find a way to track versions automatically.
369 */
370 protected static function addPackage(array &$section, $package) {
371 $versions = [
372 'composer/installers' => '^1.4',
373 'cweagans/composer-patches' => '^1.6',
374 'drupal-composer/drupal-scaffold' => '^2.5',
375 'drupal/console' => '^1.0',
376 'drupal/core' => self::DRUPAL_DEFAULT_VERSION,
377 'drupal/drupal-extension' => '^3.4',
378 'drush/drush' => '^9.6',
379 'oomphinc/composer-installers-extender' => '^1.1',
380 'symfony/dotenv' => '^3.4',
381 'webflo/drupal-core-require-dev' => self::DRUPAL_DEFAULT_VERSION,
382 'webflo/drupal-core-strict' => self::DRUPAL_DEFAULT_VERSION,
383 'wikimedia/composer-merge-plugin' => '^1.4',
384 'zaporylie/composer-drupal-optimizations' => '^1.1',
385 ];
386 $section[$package] = $versions[$package];
387 }
388
389 }