diff --git a/.drone.yml b/.drone.yml index 32a20290..41538e58 100644 --- a/.drone.yml +++ b/.drone.yml @@ -15,7 +15,10 @@ pipeline: volumes: - /cache:/cache commands: - - composer update --prefer-lowest --ansi + # @todo remove "composer install" step once the following issue is fixed. + # @link https://webgate.ec.europa.eu/CITnet/jira/browse/OPENEUROPA-1234 + - composer install --ansi --no-suggest --no-progress + - composer update --prefer-lowest --ansi --no-suggest --no-progress when: matrix: COMPOSER_BOUNDARY: lowest @@ -26,7 +29,7 @@ pipeline: volumes: - /cache:/cache commands: - - composer install --ansi + - composer install --ansi --no-suggest --no-progress when: matrix: COMPOSER_BOUNDARY: highest diff --git a/composer.json b/composer.json index c1c3099a..3daf81a1 100644 --- a/composer.json +++ b/composer.json @@ -5,7 +5,7 @@ "minimum-stability": "dev", "prefer-stable": true, "require": { - "consolidation/robo": "^1.2.2", + "consolidation/robo": "^1.3", "gitonomy/gitlib": "^1.0", "nuvoleweb/robo-config": "^0.2.1", "jakeasmith/http_build_url": "^1.0.1" diff --git a/config/commands/drupal.yml b/config/commands/drupal.yml index 4d72932f..0610838a 100644 --- a/config/commands/drupal.yml +++ b/config/commands/drupal.yml @@ -27,3 +27,8 @@ command: drush-setup: options: config-dir: ${drupal.root}/drush + settings-setup: + options: + sites-subdir: ${drupal.site.sites_subdir} + settings-override-file: ${drupal.site.settings_override_file} + force: ${drupal.site.force} diff --git a/config/runner.yml b/config/runner.yml index 9475e9d2..07af8532 100644 --- a/config/runner.yml +++ b/config/runner.yml @@ -32,6 +32,7 @@ drupal: locale: "en" sites_subdir: "default" config_dir: ~ + settings_override_file: "settings.override.php" # Administrator account information. account: diff --git a/src/Commands/DrupalCommands.php b/src/Commands/DrupalCommands.php index 88e7e29b..04e0e962 100644 --- a/src/Commands/DrupalCommands.php +++ b/src/Commands/DrupalCommands.php @@ -134,7 +134,7 @@ public function siteInstall(array $options = [ } $drush = $this->getConfig()->get('runner.bin_dir').'/drush'; - $task = $this->taskDrush($drush) + $task = $this->taskDrush($drush) ->root($options['root']) ->siteName($options['site-name']) ->siteMail($options['site-mail']) @@ -255,11 +255,13 @@ public function drushSetup(array $options = [ } /** - * Setup default Drupal settings file. + * Setup Drupal settings overrides. * - * This command will append settings specified at "drupal.settings" to the - * current site's "default.settings.php" which, in turn, will be used - * to generate the actual "settings.php" at installation time. + * This command will: + * + * - Copy "default.settings.php" to "settings.php", which will be overridden if existing + * - Append to "settings.php" an include operation for a "settings.override.php" file + * - Write settings specified at "drupal.settings" in "settings.override.php" * * Default settings can be customized in your local runner.yml.dist/runner.yml * as shown below: @@ -270,20 +272,61 @@ public function drushSetup(array $options = [ * > sync: '../config/sync' * > prod: '../config/prod' * + * The settings override file name can be changed in the Task Runner + * configuration by setting the "drupal.site.settings_override_file" property. + * * @command drupal:settings-setup * - * @option root Drupal root. + * @option root Drupal root. + * @option sites-subdir Drupal site subdirectory. + * @option settings-override-file Drupal site settings override filename. + * @option force Drupal force generation of a new settings.php. * * @param array $options * * @return \Robo\Collection\CollectionBuilder */ public function settingsSetup(array $options = [ - 'root' => InputOption::VALUE_REQUIRED, + 'root' => InputOption::VALUE_REQUIRED, + 'sites-subdir' => InputOption::VALUE_REQUIRED, + 'settings-override-file' => InputOption::VALUE_REQUIRED, + 'force' => false, ]) { - return $this->collectionBuilder()->addTaskList([ - $this->taskAppendConfiguration($options['root'].'/sites/default/default.settings.php', $this->getConfig())->setConfigKey('drupal.settings'), - ]); + $settings_default_path = $options['root'] . '/sites/' . $options['sites-subdir'] . '/default.settings.php'; + $settings_path = $options['root'] . '/sites/' . $options['sites-subdir'] . '/settings.php'; + $settings_override_path = $options['root'] . '/sites/' . $options['sites-subdir'] . '/' . $options['settings-override-file']; + + // Save the filename of the override file in a single variable to use it + // in the heredoc variable $custom_config hereunder. + $settings_override_filename = $options['settings-override-file']; + + $custom_config = <<< EOF + +/** + * Include Drupal settings overrides. + * + * The following file is generated by the openeuropa/task-runner project + * using configuration from your local "runner.yml.dist/runner.yml" files. + * + * Keep this code block at the end of the file. + */ +if (file_exists(\$app_root . '/' . \$site_path . '/$settings_override_filename')) { + include \$app_root . '/' . \$site_path . '/$settings_override_filename'; +} +EOF; + $collection = []; + + if (true === (bool) $options['force'] || !file_exists($settings_path)) { + $collection[] = $this->taskFilesystemStack()->copy($settings_default_path, $settings_path, true); + $collection[] = $this->taskWriteToFile($settings_path)->append()->lines([$custom_config]); + } + + $collection[] = $this->taskWriteConfiguration( + $settings_override_path, + $this->getConfig() + )->setConfigKey('drupal.settings'); + + return $this->collectionBuilder()->addTaskList($collection); } } diff --git a/tests/AbstractTest.php b/tests/AbstractTest.php index fcbc5220..ef3134ad 100644 --- a/tests/AbstractTest.php +++ b/tests/AbstractTest.php @@ -79,4 +79,18 @@ protected function getSandboxRoot() { return __DIR__."/sandbox"; } + + /** + * Generate a random string. + * + * @param int $length + * The desired length. + * + * @return string + * The random string. + */ + protected function generateRandomString($length = 10) + { + return substr(str_shuffle(str_repeat($x = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', ceil($length/strlen($x)))), 1, $length); + } } diff --git a/tests/CommandsTest.php b/tests/CommandsTest.php index c2fd08a9..a34fdd6f 100644 --- a/tests/CommandsTest.php +++ b/tests/CommandsTest.php @@ -146,15 +146,98 @@ public function testSettingsSetup(array $config, array $expected) file_put_contents($configFile, Yaml::dump($config)); + $sites_subdir = isset($config['drupal']['site']['sites_subdir']) ? $config['drupal']['site']['sites_subdir'] : 'default'; + mkdir($this->getSandboxRoot() . '/build/sites/' . $sites_subdir . '/', 0777, true); + file_put_contents($this->getSandboxRoot() . '/build/sites/' . $sites_subdir . '/default.settings.php', ''); + $input = new StringInput("drupal:settings-setup --working-dir=".$this->getSandboxRoot()); $runner = new TaskRunner($input, new BufferedOutput(), $this->getClassLoader()); $runner->run(); + foreach ($expected as $row) { + $content = file_get_contents($this->getSandboxFilepath($row['file'])); + $this->assertContainsNotContains($content, $row); + } + + // Generate a random function name. + $fct = $this->generateRandomString(20); + + // Generate a dummy PHP code. + $config_override_dummy_script = <<< EOF +getSandboxRoot() . '/build/sites/' . $sites_subdir . '/' . $config_override_filename, + $config_override_dummy_script + ); + + // Include the config override file. + include_once $this->getSandboxRoot() . '/build/sites/' . $sites_subdir . '/' . $config_override_filename; + + // Test if the dummy PHP code has been properly included. + $this->assertTrue(\function_exists($fct)); + } + + /** + * @param array $config + * @param array $expected + * + * @dataProvider settingsSetupForceDataProvider + */ + public function testSettingsSetupForce(array $config, array $expected) + { + $configFile = $this->getSandboxFilepath('runner.yml'); + file_put_contents($configFile, Yaml::dump($config)); + + $sites_subdir = isset($config['drupal']['site']['sites_subdir']) ? $config['drupal']['site']['sites_subdir'] : 'default'; + mkdir($this->getSandboxRoot() . '/build/sites/' . $sites_subdir . '/', 0777, true); + file_put_contents($this->getSandboxRoot() . '/build/sites/' . $sites_subdir . '/default.settings.php', ''); + file_put_contents($this->getSandboxRoot() . '/build/sites/' . $sites_subdir . '/settings.php', '# Already existing file.'); + + $input = new StringInput('drupal:settings-setup --working-dir=' . $this->getSandboxRoot()); + + if (true === $config['drupal']['site']['force']) { + $input = new StringInput('drupal:settings-setup --working-dir=' . $this->getSandboxRoot() . ' --force'); + } + $runner = new TaskRunner($input, new BufferedOutput(), $this->getClassLoader()); + $runner->run(); foreach ($expected as $row) { $content = file_get_contents($this->getSandboxFilepath($row['file'])); $this->assertContainsNotContains($content, $row); } + + // Generate a random function name. + $fct = $this->generateRandomString(20); + + // Generate a dummy PHP code. + $config_override_dummy_script = <<< EOF +getSandboxRoot() . '/build/sites/' . $sites_subdir . '/' . $config_override_filename, + $config_override_dummy_script + ); + + // Include the config override file. + include_once $this->getSandboxRoot() . '/build/sites/' . $sites_subdir . '/' . $config_override_filename; + + // Test if the dummy PHP code has been properly included. + $this->assertTrue(\function_exists($fct)); } /** @@ -200,6 +283,14 @@ public function settingsSetupDataProvider() return $this->getFixtureContent('commands/drupal-settings-setup.yml'); } + /** + * @return array + */ + public function settingsSetupForceDataProvider() + { + return $this->getFixtureContent('commands/drupal-settings-setup-force.yml'); + } + /** * @return array */ @@ -223,8 +314,8 @@ public function changelogDataProvider() protected function assertContainsNotContains($content, array $expected) { $this->assertContains($expected['contains'], $content); - if (!empty($row['not_contains'])) { - $this->assertNotContains($row['not_contains'], $content); + if (!empty($expected['not_contains'])) { + $this->assertNotContains($expected['not_contains'], $content); } } } diff --git a/tests/fixtures/commands/drupal-settings-setup-force.yml b/tests/fixtures/commands/drupal-settings-setup-force.yml new file mode 100644 index 00000000..be04d9d7 --- /dev/null +++ b/tests/fixtures/commands/drupal-settings-setup-force.yml @@ -0,0 +1,17 @@ +- configuration: + drupal: + site: + force: false + expected: + - file: "build/sites/default/settings.php" + contains: "# Already existing file." + not_contains: "include $app_root . '/' . $site_path . '/settings.override.php';" + +- configuration: + drupal: + site: + force: true + expected: + - file: "build/sites/default/settings.php" + contains: "include $app_root . '/' . $site_path . '/settings.override.php';" + not_contains: "# Already existing file." diff --git a/tests/fixtures/commands/drupal-settings-setup.yml b/tests/fixtures/commands/drupal-settings-setup.yml index 58ae4355..53938b35 100644 --- a/tests/fixtures/commands/drupal-settings-setup.yml +++ b/tests/fixtures/commands/drupal-settings-setup.yml @@ -8,9 +8,12 @@ - "vendor" - "${drupal.root}" expected: - - file: "build/sites/default/default.settings.php" + - file: "build/sites/default/settings.override.php" contains: "$conf[\"file_scan_ignore_directories\"] = array(0 => 'node_modules',1 => 'bower_components',2 => 'vendor',3 => 'build');" not_contains: ~ + - file: "build/sites/default/settings.php" + contains: "include $app_root . '/' . $site_path . '/settings.override.php';" + not_contains: ~ - configuration: drupal: @@ -19,7 +22,7 @@ file_scan_ignore_directories: - "${drupal.root}" expected: - - file: "build/sites/default/default.settings.php" + - file: "build/sites/default/settings.override.php" contains: "$settings[\"file_scan_ignore_directories\"] = array(0 => 'build');" not_contains: ~ @@ -27,6 +30,39 @@ drupal: settings: [] expected: - - file: "build/sites/default/default.settings.php" + - file: "build/sites/default/settings.override.php" contains: "// Start settings processor block." not_contains: "file_scan_ignore_directories" + +- configuration: + drupal: + settings: + settings: + file_scan_ignore_directories: + - "${drupal.root}" + site: + settings_override_file: "settings.overridemeplease.php" + expected: + - file: "build/sites/default/settings.overridemeplease.php" + contains: "$settings[\"file_scan_ignore_directories\"] = array(0 => 'build');" + not_contains: ~ + - file: "build/sites/default/settings.php" + contains: "include $app_root . '/' . $site_path . '/settings.overridemeplease.php';" + not_contains: ~ + +- configuration: + drupal: + settings: + settings: + file_scan_ignore_directories: + - "${drupal.root}" + site: + sites_subdir: "inea" + settings_override_file: "settings.overridemeplease.php" + expected: + - file: "build/sites/inea/settings.overridemeplease.php" + contains: "$settings[\"file_scan_ignore_directories\"] = array(0 => 'build');" + not_contains: ~ + - file: "build/sites/inea/settings.php" + contains: "include $app_root . '/' . $site_path . '/settings.overridemeplease.php';" + not_contains: ~ diff --git a/tests/fixtures/simulation.yml b/tests/fixtures/simulation.yml index e8651cbe..2620451e 100644 --- a/tests/fixtures/simulation.yml +++ b/tests/fixtures/simulation.yml @@ -256,13 +256,13 @@ configuration: [] composer: '' contains: - - "AppendConfiguration('build/sites/default/default.settings.php'" + - "WriteConfiguration('build/sites/default/settings.override.php'" - command: 'drupal:settings-setup --root=web' configuration: [] composer: '' contains: - - "AppendConfiguration('web/sites/default/default.settings.php'" + - "WriteConfiguration('web/sites/default/settings.override.php'" - command: 'drupal:site-setup' configuration: