diff --git a/.vortex/.ahoy.yml b/.vortex/.ahoy.yml index 55e1af10e..c6b246931 100644 --- a/.vortex/.ahoy.yml +++ b/.vortex/.ahoy.yml @@ -37,10 +37,14 @@ commands: lint: name: Lint Vortex project. cmd: | + ahoy lint-installer ahoy lint-scripts ahoy lint-dockerfiles ahoy test-docs + lint-installer: + cmd: composer --working-dir installer lint + lint-scripts: cmd: ./tests/lint.scripts.sh diff --git a/.vortex/installer/src/Command/InstallCommand.php b/.vortex/installer/src/Command/InstallCommand.php index b1f186dc2..c20a7a09d 100644 --- a/.vortex/installer/src/Command/InstallCommand.php +++ b/.vortex/installer/src/Command/InstallCommand.php @@ -368,6 +368,7 @@ protected function replaceTokens(): void { 'webroot', 'profile', 'provision_use_profile', + 'theme', 'database_download_source', 'database_image', 'override_existing_db', diff --git a/.vortex/installer/src/Traits/PromptsTrait.php b/.vortex/installer/src/Traits/PromptsTrait.php index 018ac9919..045ed834f 100644 --- a/.vortex/installer/src/Traits/PromptsTrait.php +++ b/.vortex/installer/src/Traits/PromptsTrait.php @@ -179,6 +179,23 @@ protected function processDatabaseDownloadSource(string $dir): void { } } + protected function processTheme(string $dir): void { + $webroot = $this->getAnswer('webroot'); + $name = $this->getAnswer('theme'); + + File::fileReplaceContent('/DRUPAL_THEME=.*/', 'DRUPAL_THEME=' . $name, $dir . '/.env'); + + $file_dst = $this->findThemeFile($this->config->getDstDir(), $webroot); + // Do not update the theme files if it is not a theme from the Vortex + // template. + if (!empty($file_dst) && !$this->isVortexTheme(dirname($file_dst))) { + $file_tmpl = $this->findThemeFile($dir, $webroot); + if (!empty($file_tmpl)) { + File::rmdirRecursive(dirname($file_tmpl)); + } + } + } + protected function processDatabaseImage(string $dir): void { $image = $this->getAnswer('database_image'); File::fileReplaceContent('/VORTEX_DB_IMAGE=.*/', 'VORTEX_DB_IMAGE=' . $image, $dir . '/.env'); @@ -531,33 +548,66 @@ protected function discoverValueProfile(): ?string { protected function discoverValueTheme(): ?string { $webroot = $this->getAnswer('webroot'); + $name_from_env = NULL; if ($this->isInstalled()) { - $name = $this->getValueFromDstDotenv('DRUPAL_THEME'); - if (!empty($name)) { - return $name; + $name_from_env = $this->getValueFromDstDotenv('DRUPAL_THEME'); + } + + $file = $this->findThemeFile($this->config->getDstDir(), $webroot); + + if (empty($file)) { + // If theme file was not found, but the theme is set in the .env file - + // return the theme name from the .env file. + return $name_from_env ?: NULL; + } + + $name_from_info = str_replace(['.info.yml', '.info'], '', basename($file)); + + // Check that this is a theme coming originally from the Vortex template. + $dir = dirname($file); + + if (!$this->isVortexTheme($dir)) { + // If the theme is not coming from the Vortex template - return the theme + // name from the .env file. + return $name_from_env ?: NULL; + } + + if ($name_from_env) { + if ($name_from_info !== $name_from_env) { + // If the theme name from the .env file does not match the theme name + // from the theme file - return the theme name from the info file + // to update the .env file. + return $name_from_info; } + + return $name_from_env; } + return NULL; + } + + protected function findThemeFile(string $dir, string $webroot): ?string { $locations = [ - $this->config->getDstDir() . sprintf('/%s/themes/custom/*/*.info', $webroot), - $this->config->getDstDir() . sprintf('/%s/themes/custom/*/*.info.yml', $webroot), - $this->config->getDstDir() . sprintf('/%s/sites/all/themes/custom/*/*.info', $webroot), - $this->config->getDstDir() . sprintf('/%s/sites/all/themes/custom/*/*.info.yml', $webroot), - $this->config->getDstDir() . sprintf('/%s/profiles/*/themes/custom/*/*.info', $webroot), - $this->config->getDstDir() . sprintf('/%s/profiles/*/themes/custom/*/*.info.yml', $webroot), - $this->config->getDstDir() . sprintf('/%s/profiles/custom/*/themes/custom/*/*.info', $webroot), - $this->config->getDstDir() . sprintf('/%s/profiles/custom/*/themes/custom/*/*.info.yml', $webroot), + sprintf('%s/%s/themes/custom/*/*.info', $dir, $webroot), + sprintf('%s/%s/themes/custom/*/*.info.yml', $dir, $webroot), + sprintf('%s/%s/sites/all/themes/custom/*/*.info', $dir, $webroot), + sprintf('%s/%s/sites/all/themes/custom/*/*.info.yml', $dir, $webroot), + sprintf('%s/%s/profiles/*/themes/custom/*/*.info', $dir, $webroot), + sprintf('%s/%s/profiles/*/themes/custom/*/*.info.yml', $dir, $webroot), + sprintf('%s/%s/profiles/custom/*/themes/custom/*/*.info', $dir, $webroot), + sprintf('%s/%s/profiles/custom/*/themes/custom/*/*.info.yml', $dir, $webroot), ]; - $name = File::findMatchingPath($locations); - - if (empty($name)) { - return NULL; - } + return File::findMatchingPath($locations); + } - $name = basename($name); + protected function isVortexTheme(string $dir): bool { + $c1 = file_exists($dir . '/scss/_variables.scss'); + $c2 = file_exists($dir . '/Gruntfile.js'); + $c3 = file_exists($dir . '/package.json'); + $c4 = File::fileContains('build-dev', $dir . '/package.json'); - return str_replace(['.info.yml', '.info'], '', $name); + return $c1 && $c2 && $c3 && $c4; } protected function discoverValueDomain(): ?string { diff --git a/.vortex/installer/src/Traits/TuiTrait.php b/.vortex/installer/src/Traits/TuiTrait.php index 8eef2b218..05b08304e 100644 --- a/.vortex/installer/src/Traits/TuiTrait.php +++ b/.vortex/installer/src/Traits/TuiTrait.php @@ -333,6 +333,14 @@ protected function askForAnswer(string $name, string $question): void { /** * Process answers. + * + * @param string $name + * Name of the answer. + * @param string $dir + * Temporary directory where processing takes place. + * + * @return mixed + * Processed answer. */ protected function processAnswer(string $name, string $dir): mixed { return $this->executeCallback('process', $name, $dir); diff --git a/.vortex/tests/bats/_helper.bash b/.vortex/tests/bats/_helper.bash index a4f6e5573..70b0ac3ed 100644 --- a/.vortex/tests/bats/_helper.bash +++ b/.vortex/tests/bats/_helper.bash @@ -234,6 +234,7 @@ assert_files_present_common() { local suffix_abbreviated_camel_cased="${4:-Sw}" local suffix_camel_cased="${5:-StarWars}" local webroot="${6:-web}" + local assert_theme="${7:-1}" local suffix_abbreviated_uppercase="$(string_to_upper "${suffix_abbreviated}")" @@ -254,7 +255,7 @@ assert_files_present_common() { # Assert that Vortex footnote remains. assert_file_contains "README.md" "This repository was created using the [Vortex](https://github.com/drevops/vortex) project template" - assert_files_present_drupal "${dir}" "${suffix}" "${suffix_abbreviated}" "${suffix_abbreviated_camel_cased}" "${suffix_camel_cased}" "${webroot}" + assert_files_present_drupal "${dir}" "${suffix}" "${suffix_abbreviated}" "${suffix_abbreviated_camel_cased}" "${suffix_camel_cased}" "${webroot}" "${assert_theme}" popd >/dev/null || exit 1 } @@ -453,6 +454,7 @@ assert_files_present_drupal() { local suffix_abbreviated_camel_cased="${4:-Sw}" local suffix_camel_cased="${5:-StarWars}" local webroot="${6:-web}" + local assert_theme="${7:-1}" pushd "${dir}" >/dev/null || exit 1 @@ -480,27 +482,29 @@ assert_files_present_drupal() { assert_file_exists "${webroot}/modules/custom/${suffix_abbreviated}_search/${suffix_abbreviated}_search.info.yml" # Site theme created. - assert_dir_exists "${webroot}/themes/custom/${suffix}" - assert_file_exists "${webroot}/themes/custom/${suffix}/js/${suffix}.js" - assert_dir_exists "${webroot}/themes/custom/${suffix}/scss" - assert_dir_exists "${webroot}/themes/custom/${suffix}/images" - assert_dir_exists "${webroot}/themes/custom/${suffix}/fonts" - assert_file_exists "${webroot}/themes/custom/${suffix}/.gitignore" - assert_file_exists "${webroot}/themes/custom/${suffix}/${suffix}.info.yml" - assert_file_exists "${webroot}/themes/custom/${suffix}/${suffix}.libraries.yml" - assert_file_exists "${webroot}/themes/custom/${suffix}/${suffix}.theme" - assert_file_exists "${webroot}/themes/custom/${suffix}/Gruntfile.js" - assert_file_exists "${webroot}/themes/custom/${suffix}/package.json" - - assert_file_exists "${webroot}/themes/custom/${suffix}/tests/src/Unit/${suffix_camel_cased}UnitTestBase.php" - assert_file_exists "${webroot}/themes/custom/${suffix}/tests/src/Unit/ExampleTest.php" - assert_file_exists "${webroot}/themes/custom/${suffix}/tests/src/Kernel/${suffix_camel_cased}KernelTestBase.php" - assert_file_exists "${webroot}/themes/custom/${suffix}/tests/src/Kernel/ExampleTest.php" - assert_file_exists "${webroot}/themes/custom/${suffix}/tests/src/Functional/${suffix_camel_cased}FunctionalTestBase.php" - assert_file_exists "${webroot}/themes/custom/${suffix}/tests/src/Functional/ExampleTest.php" - - # Comparing binary files. - assert_binary_files_equal "${LOCAL_REPO_DIR}/web/themes/custom/your_site_theme/screenshot.png" "${webroot}/themes/custom/${suffix}/screenshot.png" + if [ "${assert_theme}" = 1 ]; then + assert_dir_exists "${webroot}/themes/custom/${suffix}" + assert_file_exists "${webroot}/themes/custom/${suffix}/js/${suffix}.js" + assert_dir_exists "${webroot}/themes/custom/${suffix}/scss" + assert_dir_exists "${webroot}/themes/custom/${suffix}/images" + assert_dir_exists "${webroot}/themes/custom/${suffix}/fonts" + assert_file_exists "${webroot}/themes/custom/${suffix}/.gitignore" + assert_file_exists "${webroot}/themes/custom/${suffix}/${suffix}.info.yml" + assert_file_exists "${webroot}/themes/custom/${suffix}/${suffix}.libraries.yml" + assert_file_exists "${webroot}/themes/custom/${suffix}/${suffix}.theme" + assert_file_exists "${webroot}/themes/custom/${suffix}/Gruntfile.js" + assert_file_exists "${webroot}/themes/custom/${suffix}/package.json" + + assert_file_exists "${webroot}/themes/custom/${suffix}/tests/src/Unit/${suffix_camel_cased}UnitTestBase.php" + assert_file_exists "${webroot}/themes/custom/${suffix}/tests/src/Unit/ExampleTest.php" + assert_file_exists "${webroot}/themes/custom/${suffix}/tests/src/Kernel/${suffix_camel_cased}KernelTestBase.php" + assert_file_exists "${webroot}/themes/custom/${suffix}/tests/src/Kernel/ExampleTest.php" + assert_file_exists "${webroot}/themes/custom/${suffix}/tests/src/Functional/${suffix_camel_cased}FunctionalTestBase.php" + assert_file_exists "${webroot}/themes/custom/${suffix}/tests/src/Functional/ExampleTest.php" + + # Comparing binary files. + assert_binary_files_equal "${LOCAL_REPO_DIR}/web/themes/custom/your_site_theme/screenshot.png" "${webroot}/themes/custom/${suffix}/screenshot.png" + fi # Drupal Scaffold files exist. assert_file_exists "${webroot}/.editorconfig" diff --git a/.vortex/tests/bats/install.existing.bats b/.vortex/tests/bats/install.existing.bats index 99efdb038..682217b6e 100644 --- a/.vortex/tests/bats/install.existing.bats +++ b/.vortex/tests/bats/install.existing.bats @@ -308,7 +308,7 @@ load _helper.bash assert_file_contains ".env.local" "some random content" } -@test "Install into existing: previously installed project; custom webroot; discovery; quiet" { +@test "Install into existing: previously installed bespoke project; custom webroot; discovery; quiet" { echo "VORTEX_WEBROOT=rootdoc" >>".env" # Populate current dir with a project at current version. @@ -323,8 +323,8 @@ load _helper.bash assert_files_present_common "" "" "" "" "" "rootdoc" } -@test "Install into existing: previously installed project; custom theme; discovery; quiet" { - echo "DRUPAL_THEME=star_wars" >>".env" +@test "Install into existing: previously installed bespoke project; custom named theme; discovery; quiet" { + echo "DRUPAL_THEME=star_wars" >> ".env" # Populate current dir with a project at current version. output=$(run_installer_quiet) @@ -338,6 +338,28 @@ load _helper.bash assert_files_present_common } +@test "Install into existing: previously installed project; bespoke theme; discovery; quiet" { + # Populate current dir with a project at current version. + output=$(run_installer_quiet) + assert_output_contains "WELCOME TO VORTEX QUIET INSTALLER" + assert_output_not_contains "It looks like Vortex is already installed into this project" + + assert_git_repo + + install_dependencies_stub + + # Replace the theme with a custom one. + rm -Rf "web/themes/custom/star_wars" + mktouch "web/themes/custom/star_wars/star_wars.info.yml" + + output=$(run_installer_quiet) + assert_output_contains "WELCOME TO VORTEX QUIET INSTALLER" + assert_output_contains "It looks like Vortex is already installed into this project" + + assert_files_present_common "" "" "" "" "" "" 0 + assert_file_not_exists "web/themes/custom/star_wars/Gruntfile.js" +} + @test "Install into existing: previously installed project; custom profile; discovery; quiet" { # Populate current dir with a project at current version. output=$(run_installer_quiet) diff --git a/.vortex/tests/bats/install.parameters.bats b/.vortex/tests/bats/install.parameters.bats index aa6eee60d..5d13cb586 100644 --- a/.vortex/tests/bats/install.parameters.bats +++ b/.vortex/tests/bats/install.parameters.bats @@ -403,7 +403,7 @@ load _helper.bash } # -# Helper to create fixture files to fake pre-installed state. +# Helper to create fixture files to fake pre-installed state from Vortex. # # Note that this helper provides only one state of the fixture site. # @@ -426,7 +426,12 @@ fixture_preinstalled() { # Sets 'theme' to 'resisting'. mktouch "${webroot}/sites/all/themes/custom/resisting/resisting.info.yml" + mktouch "${webroot}/sites/all/themes/custom/resisting/Gruntfile.js" + mktouch "${webroot}/sites/all/themes/custom/resisting/scss/_variables.scss" + mktouch "${webroot}/sites/all/themes/custom/resisting/package.json" + echo "build-dev" >>"${webroot}/sites/all/themes/custom/resisting/package.json" mktouch "${webroot}/sites/all/themes/custom/yetanothertheme/yetanothertheme.info.yml" + echo "DRUPAL_THEME=resisting" >>.env # Sets 'ci_provider' to 'GitHub Actions'. mktouch ".github/workflows/build-test-deploy.yml"