From e11f4861cf3eb4d3672354f235998f6c824897c1 Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Sat, 21 Mar 2026 16:44:01 +1100 Subject: [PATCH 01/16] p --- scripts/vortex/provision.sh | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/scripts/vortex/provision.sh b/scripts/vortex/provision.sh index 42d1867ab..d67eaa9d5 100755 --- a/scripts/vortex/provision.sh +++ b/scripts/vortex/provision.sh @@ -163,7 +163,7 @@ provision_from_db() { if [ ! -f "${VORTEX_PROVISION_DB}" ]; then if [ "${VORTEX_PROVISION_FALLBACK_TO_PROFILE}" = "1" ]; then info "Database dump file is not available. Falling back to profile installation." - provision_from_profile + provision_from_profile 1 "${site_has_config_files}" return fi @@ -186,6 +186,8 @@ provision_from_db() { # Provision site from the profile. # provision_from_profile() { + local is_fallback="${1:-0}" + local has_config="${2:-0}" local opts=() opts+=( @@ -199,13 +201,24 @@ provision_from_profile() { [ -n "${DRUPAL_ADMIN_EMAIL:-}" ] && opts+=(--account-mail="${DRUPAL_ADMIN_EMAIL:-}") - [ "${site_has_config_files}" = "1" ] && opts+=(--existing-config) + # Only use --existing-config for direct profile provisions. + [ "${is_fallback}" != "1" ] && [ "${has_config}" = "1" ] && opts+=(--existing-config) # Database may exist in non-bootstrappable state - truncate it. drush sql:drop || true drush site:install "${opts[@]}" + if [ "${is_fallback}" = "1" ] && [ "${has_config}" = "1" ]; then + note "Removing entities and config created by the profile to prevent conflicts during configuration import." + drush entity:delete shortcut_set || true + drush config:delete field.field.node.article.body || true + drush config:delete field.field.node.article.field_image || true + drush config:delete field.storage.node.field_image || true + drush config:delete taxonomy.vocabulary.tags || true + drush config:delete user.role.content_editor || true + fi + pass "Installed a site from the profile." } @@ -242,7 +255,7 @@ if [ "${VORTEX_PROVISION_TYPE}" = "database" ]; then note "Database is baked into the container image." if [ "${VORTEX_PROVISION_FALLBACK_TO_PROFILE}" = "1" ]; then info "Database in the container image is not available. Falling back to profile installation." - provision_from_profile + provision_from_profile 1 "${site_has_config_files}" export VORTEX_PROVISION_OVERRIDE_DB=1 else note "Looks like the database in the container image is corrupted." @@ -265,7 +278,7 @@ else if [ "${VORTEX_PROVISION_OVERRIDE_DB}" = "1" ]; then note "Existing site content will be removed and new content will be created from the profile." - provision_from_profile + provision_from_profile 0 "${site_has_config_files}" # Let the downstream scripts know that the database is fresh. export VORTEX_PROVISION_OVERRIDE_DB=1 else @@ -276,7 +289,7 @@ else else note "Existing site was not found." note "Fresh site content will be created from the profile." - provision_from_profile + provision_from_profile 0 "${site_has_config_files}" export VORTEX_PROVISION_OVERRIDE_DB=1 fi fi @@ -345,6 +358,10 @@ fi pass "Completed running database updates." echo +task "Clearing cache after database updates." +drush cache:rebuild +pass "Cache was cleared." + # Import configuration if config files are present. if [ "${site_has_config_files}" = "1" ]; then task "Importing configuration." From bc398d73a0c475b66649d1146a4571fa6c916b3e Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Sat, 21 Mar 2026 18:08:43 +1100 Subject: [PATCH 02/16] Added skip variable for cache rebuild after database updates. --- scripts/vortex/provision.sh | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/scripts/vortex/provision.sh b/scripts/vortex/provision.sh index d67eaa9d5..1a3a6e5c7 100755 --- a/scripts/vortex/provision.sh +++ b/scripts/vortex/provision.sh @@ -44,6 +44,9 @@ VORTEX_PROVISION_POST_OPERATIONS_SKIP="${VORTEX_PROVISION_POST_OPERATIONS_SKIP:- # drush config:import from silently overwriting those changes. VORTEX_PROVISION_VERIFY_CONFIG_UNCHANGED_AFTER_UPDATE="${VORTEX_PROVISION_VERIFY_CONFIG_UNCHANGED_AFTER_UPDATE:-0}" +# Skip cache rebuild after database updates. +VORTEX_PROVISION_CACHE_REBUILD_AFTER_DB_UPDATE_SKIP="${VORTEX_PROVISION_CACHE_REBUILD_AFTER_DB_UPDATE_SKIP:-0}" + # Provision database dump file. # If not set, it will be auto-discovered from the VORTEX_DB_DIR directory using # the VORTEX_DB_FILE name. @@ -358,9 +361,15 @@ fi pass "Completed running database updates." echo -task "Clearing cache after database updates." -drush cache:rebuild -pass "Cache was cleared." +if [ "${VORTEX_PROVISION_CACHE_REBUILD_AFTER_DB_UPDATE_SKIP}" != "1" ]; then + task "Clearing cache after database updates." + drush cache:rebuild + pass "Cache was cleared." + echo +else + pass "Skipped cache rebuild after database updates." + echo +fi # Import configuration if config files are present. if [ "${site_has_config_files}" = "1" ]; then From 46d8f80577f03e8e9f88bbec35207f261b11f216 Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Sat, 21 Mar 2026 18:35:16 +1100 Subject: [PATCH 03/16] Updated provision bats tests with cache rebuild after database updates step. --- .vortex/tests/bats/unit/provision.bats | 56 ++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/.vortex/tests/bats/unit/provision.bats b/.vortex/tests/bats/unit/provision.bats index 00a9eed71..9d9acd2dd 100644 --- a/.vortex/tests/bats/unit/provision.bats +++ b/.vortex/tests/bats/unit/provision.bats @@ -113,6 +113,11 @@ assert_provision_info() { "@drush -y updatedb --no-cache-clear" "Completed running database updates." + # Cache rebuild after database updates. + "Clearing cache after database updates." + "@drush -y cache:rebuild" + "Cache was cleared." + # Cache rebuild. "Rebuilding cache." "@drush -y cache:rebuild" @@ -248,6 +253,11 @@ assert_provision_info() { "@drush -y updatedb --no-cache-clear" "Completed running database updates." + # Cache rebuild after database updates. + "Clearing cache after database updates." + "@drush -y cache:rebuild" + "Cache was cleared." + # Cache rebuild. "Rebuilding cache." "@drush -y cache:rebuild" @@ -384,6 +394,11 @@ assert_provision_info() { "@drush -y updatedb --no-cache-clear" "Completed running database updates." + # Cache rebuild after database updates. + "Clearing cache after database updates." + "@drush -y cache:rebuild" + "Cache was cleared." + # Cache rebuild. "Rebuilding cache." "@drush -y cache:rebuild" @@ -525,6 +540,11 @@ assert_provision_info() { "@drush -y updatedb --no-cache-clear" "Completed running database updates." + # Cache rebuild after database updates. + "Clearing cache after database updates." + "@drush -y cache:rebuild" + "Cache was cleared." + # Configuration import. "Importing configuration." "@drush -y config:import" @@ -674,6 +694,11 @@ assert_provision_info() { "@drush -y updatedb --no-cache-clear" "Completed running database updates." + # Cache rebuild after database updates. + "Clearing cache after database updates." + "@drush -y cache:rebuild" + "Cache was cleared." + # Cache rebuild. "Rebuilding cache." "@drush -y cache:rebuild" @@ -812,6 +837,11 @@ assert_provision_info() { "@drush -y updatedb --no-cache-clear" "Completed running database updates." + # Cache rebuild after database updates. + "Clearing cache after database updates." + "@drush -y cache:rebuild" + "Cache was cleared." + # Cache rebuild. "Rebuilding cache." "@drush -y cache:rebuild" @@ -949,6 +979,11 @@ assert_provision_info() { "@drush -y updatedb --no-cache-clear" "Completed running database updates." + # Cache rebuild after database updates. + "Clearing cache after database updates." + "@drush -y cache:rebuild" + "Cache was cleared." + # Cache rebuild. "Rebuilding cache." "@drush -y cache:rebuild" @@ -1086,6 +1121,11 @@ assert_provision_info() { "@drush -y updatedb --no-cache-clear" "Completed running database updates." + # Cache rebuild after database updates. + "Clearing cache after database updates." + "@drush -y cache:rebuild" + "Cache was cleared." + # Cache rebuild. "Rebuilding cache." "@drush -y cache:rebuild" @@ -1253,6 +1293,11 @@ assert_provision_info() { "@drush -y updatedb --no-cache-clear" "Completed running database updates." + # Cache rebuild after database updates. + "Clearing cache after database updates." + "@drush -y cache:rebuild" + "Cache was cleared." + # Cache rebuild. "Rebuilding cache." "@drush -y cache:rebuild" @@ -1391,6 +1436,11 @@ assert_provision_info() { "@drush -y updatedb --no-cache-clear" "Completed running database updates." + # Cache rebuild after database updates. + "Clearing cache after database updates." + "@drush -y cache:rebuild" + "Cache was cleared." + # Cache rebuild. "Rebuilding cache." "@drush -y cache:rebuild" @@ -1714,6 +1764,11 @@ assert_provision_info() { "Completed running database updates." "- Configuration was changed by database updates." + # Cache rebuild after database updates. + "Clearing cache after database updates." + "@drush -y cache:rebuild" + "Cache was cleared." + # Configuration import. "Importing configuration." "@drush -y config:import" @@ -1867,6 +1922,7 @@ assert_provision_info() { # These should NOT appear (script exits before them). "- Verified that database updates did not change configuration." "- Completed running database updates." + "- Clearing cache after database updates." "- Importing configuration." "- Rebuilding cache." "- Running deployment hooks." From 47b0f20cb48b51ee276651f92e19528c2796cd8c Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Sat, 21 Mar 2026 18:35:47 +1100 Subject: [PATCH 04/16] Updated provision documentation with fallback behavior and cache rebuild skip variable. --- .vortex/docs/content/drupal/provision.mdx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.vortex/docs/content/drupal/provision.mdx b/.vortex/docs/content/drupal/provision.mdx index 34b8f0856..ea8098ce5 100644 --- a/.vortex/docs/content/drupal/provision.mdx +++ b/.vortex/docs/content/drupal/provision.mdx @@ -136,6 +136,8 @@ section. ⑦ 💡 Verify config unchanged? ──Config changed──► 🏁 EXIT 1 (fail) ✗ │ Config unchanged (or check disabled) ▼ +⑨ 🧹 Rebuild caches after DB updates (skippable) + ▼ ⬇️ Import configuration (if config files present) ▼ 🧹 Rebuild caches @@ -158,11 +160,12 @@ You can control the provisioning flow using the following environment variables: 1. `VORTEX_PROVISION_SKIP=1`
Kill-switch to completely skip provisioning. The script will exit immediately after start. Useful in emergencies when any kind of automation needs to be disabled.

2. `VORTEX_PROVISION_TYPE=profile`
Install from a Drupal `profile` instead of importing from a `database` dump. Useful for building sites without the persistent DB and/or test profile configuration installation.

3. `VORTEX_PROVISION_OVERRIDE_DB=1`
Drop an existing database before importing from dump/installing from profile. This is useful when an already provisioned environment requires a fresh database to be imported.

-4. `VORTEX_PROVISION_FALLBACK_TO_PROFILE=1`
Automatically fall back to installing from profile if the database dump file or container image is not available. Useful for distribution demos or when using recipes/profiles that can install without a pre-existing database.

+4. `VORTEX_PROVISION_FALLBACK_TO_PROFILE=1`
Automatically fall back to installing from profile if the database dump file or container image is not available. When falling back, the `--existing-config` flag is not used during `drush site:install` because profiles with `hook_install()` (like `standard`) cannot be installed from configuration. Any entities created by the profile's `hook_install()` are automatically removed to prevent conflicts during the subsequent configuration import step. Useful for distribution demos or when using recipes/profiles that can install without a pre-existing database.

5. `VORTEX_PROVISION_POST_OPERATIONS_SKIP=1`
Skip configuration imports, database updates, and other post-provisioning steps. Essentially, this is `drush sql:drop` and `$(drush sql:connect) < .data/db.sql` commands. This is useful when you want to provision a site without running any additional operations.
`ahoy import-db` uses this flag to import DB and exit.

6. `VORTEX_PROVISION_USE_MAINTENANCE_MODE=1`
Enable maintenance mode right after the site is bootstrappable and disable it at the end. Useful when you want to prevent users from accessing the site while it is being provisioned.

7. `VORTEX_PROVISION_VERIFY_CONFIG_UNCHANGED_AFTER_UPDATE=1`
Verify that active configuration was not changed by database updates. When enabled and config files are present, the provision will fail if `drush updatedb` modifies active configuration, preventing `drush config:import` from silently overwriting those changes.

-8. `VORTEX_PROVISION_SANITIZE_DB_SKIP=1`
Disable database sanitization. +8. `VORTEX_PROVISION_SANITIZE_DB_SKIP=1`
Disable database sanitization.

+9. `VORTEX_PROVISION_CACHE_REBUILD_AFTER_DB_UPDATE_SKIP=1`
Skip the cache rebuild that runs between database updates and configuration import. By default, caches are rebuilt after `drush updatedb` to ensure a clean state before importing configuration. :::tip From f9b15bbac94620ec2905c4239124640edc1e39fa Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Sat, 21 Mar 2026 18:42:01 +1100 Subject: [PATCH 05/16] Regenerated variables documentation. --- .vortex/docs/content/development/variables.mdx | 1 + 1 file changed, 1 insertion(+) diff --git a/.vortex/docs/content/development/variables.mdx b/.vortex/docs/content/development/variables.mdx index 1997995e3..49b07f9e0 100644 --- a/.vortex/docs/content/development/variables.mdx +++ b/.vortex/docs/content/development/variables.mdx @@ -387,6 +387,7 @@ The list below is automatically generated with [Shellvar](https://github.com/ale | `VORTEX_NOTIFY_WEBHOOK_URL` | Webhook URL to send notifications to. | `UNDEFINED` | `.env`, `scripts/vortex/notify-webhook.sh`, `ACQUIA ENVIRONMENT`, `LAGOON ENVIRONMENT` | | `VORTEX_PROJECT` | Project name.

Drives internal naming within the codebase. Does not affect the names of containers and development URL - those depend on the project directory and can be overridden with [`$COMPOSE_PROJECT_NAME`](#compose_project_name). | `your_site` | `.env`, `scripts/vortex/info.sh` | | `VORTEX_PROVISION_ACQUIA_SKIP` | Skip Drupal site provisioning in Acquia environment. | `UNDEFINED` | `ACQUIA ENVIRONMENT` | +| `VORTEX_PROVISION_CACHE_REBUILD_AFTER_DB_UPDATE_SKIP` | Skip cache rebuild after database updates. | `0` | `scripts/vortex/provision.sh` | | `VORTEX_PROVISION_DB` | Provision database dump file. If not set, it will be auto-discovered from the VORTEX_DB_DIR directory using the VORTEX_DB_FILE name. | `UNDEFINED` | `scripts/vortex/provision.sh` | | `VORTEX_PROVISION_DB_DIR` | Directory with database dump file. | `./.data` | `scripts/vortex/provision.sh` | | `VORTEX_PROVISION_DB_FILE` | Database dump file name. | `db.sql` | `scripts/vortex/provision.sh` | From 238b626f1cd375942a9f7b8e6440c45439c21bfe Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Sat, 21 Mar 2026 18:50:27 +1100 Subject: [PATCH 06/16] Added functional test for provision fallback to profile with config files. --- .../Functional/ProvisionFallbackTest.php | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 .vortex/tests/phpunit/Functional/ProvisionFallbackTest.php diff --git a/.vortex/tests/phpunit/Functional/ProvisionFallbackTest.php b/.vortex/tests/phpunit/Functional/ProvisionFallbackTest.php new file mode 100644 index 000000000..0bc68fa58 --- /dev/null +++ b/.vortex/tests/phpunit/Functional/ProvisionFallbackTest.php @@ -0,0 +1,86 @@ +dockerCleanup(); + } + + #[Group('p0')] + public function testProvisionFallbackToProfile(): void { + static::$sutInstallerEnv = ['VORTEX_INSTALLER_IS_DEMO' => '1']; + $this->prepareSut(); + $this->adjustAhoyForUnmountedVolumes(); + + $this->logSubstep('Build the site with database dump'); + $this->subtestAhoyBuild(); + + $this->logSubstep('Export configuration from the provisioned site'); + $this->cmd('ahoy drush cex -y', '* ../config/default', 'Export configuration should complete successfully'); + $this->syncToHost('config'); + $this->assertFilesWildcardExists('config/default/*.yml'); + + $this->logSubstep('Remove the database dump file'); + $this->removePathHostAndContainer('.data/db.sql'); + $this->assertFileDoesNotExist('.data/db.sql', 'Database dump file should not exist after removal'); + + $this->logSubstep('Drop the database to simulate a fresh environment'); + $this->cmd('ahoy drush sql:drop -y', txt: 'Database should be dropped successfully'); + + $this->logSubstep('Provision without fallback should fail'); + $this->fileAddVar('.env', 'VORTEX_PROVISION_FALLBACK_TO_PROFILE', 0); + $this->syncToContainer(['.env']); + $this->cmdFail( + 'ahoy provision', + [ + '* Unable to import database from file', + '* does not exist', + '* Site content was not changed', + ], + 'Provision without fallback should fail when no database dump is available', + ); + + $this->logSubstep('Provision with fallback should succeed'); + $this->fileAddVar('.env', 'VORTEX_PROVISION_FALLBACK_TO_PROFILE', 1); + $this->syncToContainer(['.env']); + $this->cmd( + 'ahoy provision', + [ + '* Database dump file is not available. Falling back to profile installation', + '* Installed a site from the profile', + '* Removing entities and config created by the profile to prevent conflicts during configuration import', + '* Importing configuration', + '* Completed configuration import', + '* Running deployment hooks', + ], + 'Provision with fallback should complete successfully', + tio: 15 * 60, + ); + + $this->logSubstep('Assert that required modules are enabled'); + $this->cmd('ahoy drush pm:list --status=enabled --type=module --format=list', '* ys_demo', 'ys_demo module should be enabled after fallback provision'); + + $this->logSubstep('Assert that homepage does not contain database dump content'); + $this->assertWebpageNotContains('/', 'This demo page is sourced from the Vortex database dump file', 'Homepage should not show database dump content after fallback provision'); + + $this->logSubstep('Assert that homepage is accessible'); + $this->assertWebpageContains('/', ' Date: Sat, 21 Mar 2026 18:58:21 +1100 Subject: [PATCH 07/16] Moved provision fallback test into 'AhoyWorkflowTest'. --- .../phpunit/Functional/AhoyWorkflowTest.php | 61 +++++++++++++ .../Functional/ProvisionFallbackTest.php | 86 ------------------- 2 files changed, 61 insertions(+), 86 deletions(-) delete mode 100644 .vortex/tests/phpunit/Functional/ProvisionFallbackTest.php diff --git a/.vortex/tests/phpunit/Functional/AhoyWorkflowTest.php b/.vortex/tests/phpunit/Functional/AhoyWorkflowTest.php index 1ea7a6e85..84c02ce9a 100644 --- a/.vortex/tests/phpunit/Functional/AhoyWorkflowTest.php +++ b/.vortex/tests/phpunit/Functional/AhoyWorkflowTest.php @@ -442,4 +442,65 @@ public function testAhoyUpdateVortexRef(): void { $this->assertFileDoesNotExist('installer.php', 'Installer script should be removed after update'); } + #[Group('p0')] + public function testAhoyWorkflowProvisionFallbackToProfile(): void { + static::$sutInstallerEnv = ['VORTEX_INSTALLER_IS_DEMO' => '1']; + $this->prepareSut(); + $this->adjustAhoyForUnmountedVolumes(); + + $this->logSubstep('Build the site with database dump'); + $this->subtestAhoyBuild(); + + $this->logSubstep('Export configuration from the provisioned site'); + $this->cmd('ahoy drush cex -y', '* ../config/default', 'Export configuration should complete successfully'); + $this->syncToHost('config'); + $this->assertFilesWildcardExists('config/default/*.yml'); + + $this->logSubstep('Remove the database dump file'); + $this->removePathHostAndContainer('.data/db.sql'); + $this->assertFileDoesNotExist('.data/db.sql', 'Database dump file should not exist after removal'); + + $this->logSubstep('Drop the database to simulate a fresh environment'); + $this->cmd('ahoy drush sql:drop -y', txt: 'Database should be dropped successfully'); + + $this->logSubstep('Provision without fallback should fail'); + $this->fileAddVar('.env', 'VORTEX_PROVISION_FALLBACK_TO_PROFILE', 0); + $this->syncToContainer(['.env']); + $this->cmdFail( + 'ahoy provision', + [ + '* Unable to import database from file', + '* does not exist', + '* Site content was not changed', + ], + 'Provision without fallback should fail when no database dump is available', + ); + + $this->logSubstep('Provision with fallback should succeed'); + $this->fileAddVar('.env', 'VORTEX_PROVISION_FALLBACK_TO_PROFILE', 1); + $this->syncToContainer(['.env']); + $this->cmd( + 'ahoy provision', + [ + '* Database dump file is not available. Falling back to profile installation', + '* Installed a site from the profile', + '* Removing entities and config created by the profile to prevent conflicts during configuration import', + '* Importing configuration', + '* Completed configuration import', + '* Running deployment hooks', + ], + 'Provision with fallback should complete successfully', + tio: 15 * 60, + ); + + $this->logSubstep('Assert that required modules are enabled'); + $this->cmd('ahoy drush pm:list --status=enabled --type=module --format=list', '* ys_demo', 'ys_demo module should be enabled after fallback provision'); + + $this->logSubstep('Assert that homepage does not contain database dump content'); + $this->assertWebpageNotContains('/', 'This demo page is sourced from the Vortex database dump file', 'Homepage should not show database dump content after fallback provision'); + + $this->logSubstep('Assert that homepage is accessible'); + $this->assertWebpageContains('/', 'dockerCleanup(); - } - - #[Group('p0')] - public function testProvisionFallbackToProfile(): void { - static::$sutInstallerEnv = ['VORTEX_INSTALLER_IS_DEMO' => '1']; - $this->prepareSut(); - $this->adjustAhoyForUnmountedVolumes(); - - $this->logSubstep('Build the site with database dump'); - $this->subtestAhoyBuild(); - - $this->logSubstep('Export configuration from the provisioned site'); - $this->cmd('ahoy drush cex -y', '* ../config/default', 'Export configuration should complete successfully'); - $this->syncToHost('config'); - $this->assertFilesWildcardExists('config/default/*.yml'); - - $this->logSubstep('Remove the database dump file'); - $this->removePathHostAndContainer('.data/db.sql'); - $this->assertFileDoesNotExist('.data/db.sql', 'Database dump file should not exist after removal'); - - $this->logSubstep('Drop the database to simulate a fresh environment'); - $this->cmd('ahoy drush sql:drop -y', txt: 'Database should be dropped successfully'); - - $this->logSubstep('Provision without fallback should fail'); - $this->fileAddVar('.env', 'VORTEX_PROVISION_FALLBACK_TO_PROFILE', 0); - $this->syncToContainer(['.env']); - $this->cmdFail( - 'ahoy provision', - [ - '* Unable to import database from file', - '* does not exist', - '* Site content was not changed', - ], - 'Provision without fallback should fail when no database dump is available', - ); - - $this->logSubstep('Provision with fallback should succeed'); - $this->fileAddVar('.env', 'VORTEX_PROVISION_FALLBACK_TO_PROFILE', 1); - $this->syncToContainer(['.env']); - $this->cmd( - 'ahoy provision', - [ - '* Database dump file is not available. Falling back to profile installation', - '* Installed a site from the profile', - '* Removing entities and config created by the profile to prevent conflicts during configuration import', - '* Importing configuration', - '* Completed configuration import', - '* Running deployment hooks', - ], - 'Provision with fallback should complete successfully', - tio: 15 * 60, - ); - - $this->logSubstep('Assert that required modules are enabled'); - $this->cmd('ahoy drush pm:list --status=enabled --type=module --format=list', '* ys_demo', 'ys_demo module should be enabled after fallback provision'); - - $this->logSubstep('Assert that homepage does not contain database dump content'); - $this->assertWebpageNotContains('/', 'This demo page is sourced from the Vortex database dump file', 'Homepage should not show database dump content after fallback provision'); - - $this->logSubstep('Assert that homepage is accessible'); - $this->assertWebpageContains('/', ' Date: Sat, 21 Mar 2026 19:45:27 +1100 Subject: [PATCH 08/16] Fixed shortcut entity deletion to use direct SQL instead of 'drush entity:delete'. --- scripts/vortex/provision.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/scripts/vortex/provision.sh b/scripts/vortex/provision.sh index 1a3a6e5c7..a40f69f93 100755 --- a/scripts/vortex/provision.sh +++ b/scripts/vortex/provision.sh @@ -214,7 +214,13 @@ provision_from_profile() { if [ "${is_fallback}" = "1" ] && [ "${has_config}" = "1" ]; then note "Removing entities and config created by the profile to prevent conflicts during configuration import." - drush entity:delete shortcut_set || true + # Use direct SQL to delete shortcut entities to avoid triggering hooks + # from modules that are not yet installed (e.g., redirect module's + # redirect_delete_by_path() queries a table that does not exist). + drush sql:query "DELETE FROM shortcut_set_users" || true + drush sql:query "DELETE FROM shortcut_field_data" || true + drush sql:query "DELETE FROM shortcut" || true + drush sql:query "DELETE FROM config WHERE name LIKE 'shortcut.set.%'" || true drush config:delete field.field.node.article.body || true drush config:delete field.field.node.article.field_image || true drush config:delete field.storage.node.field_image || true From b5d5c46fb14b7191f13a2e316c3ce29d9d0a7eb2 Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Sat, 21 Mar 2026 20:17:42 +1100 Subject: [PATCH 09/16] Fixed demo module name in fallback test to use SUT prefix. --- .vortex/tests/phpunit/Functional/AhoyWorkflowTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vortex/tests/phpunit/Functional/AhoyWorkflowTest.php b/.vortex/tests/phpunit/Functional/AhoyWorkflowTest.php index 84c02ce9a..a042d85b8 100644 --- a/.vortex/tests/phpunit/Functional/AhoyWorkflowTest.php +++ b/.vortex/tests/phpunit/Functional/AhoyWorkflowTest.php @@ -494,7 +494,7 @@ public function testAhoyWorkflowProvisionFallbackToProfile(): void { ); $this->logSubstep('Assert that required modules are enabled'); - $this->cmd('ahoy drush pm:list --status=enabled --type=module --format=list', '* ys_demo', 'ys_demo module should be enabled after fallback provision'); + $this->cmd('ahoy drush pm:list --status=enabled --type=module --format=list', '* sw_demo', 'Demo module should be enabled after fallback provision'); $this->logSubstep('Assert that homepage does not contain database dump content'); $this->assertWebpageNotContains('/', 'This demo page is sourced from the Vortex database dump file', 'Homepage should not show database dump content after fallback provision'); From 67a6c62d730d7c96c8666a8c8d86597287c77aec Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Sat, 21 Mar 2026 23:24:44 +1100 Subject: [PATCH 10/16] Fixed provision documentation numbering to match flow order. --- .vortex/docs/content/drupal/provision.mdx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.vortex/docs/content/drupal/provision.mdx b/.vortex/docs/content/drupal/provision.mdx index ea8098ce5..65e6e56a5 100644 --- a/.vortex/docs/content/drupal/provision.mdx +++ b/.vortex/docs/content/drupal/provision.mdx @@ -136,7 +136,7 @@ section. ⑦ 💡 Verify config unchanged? ──Config changed──► 🏁 EXIT 1 (fail) ✗ │ Config unchanged (or check disabled) ▼ -⑨ 🧹 Rebuild caches after DB updates (skippable) +⑧ 🧹 Rebuild caches after DB updates (skippable) ▼ ⬇️ Import configuration (if config files present) ▼ @@ -144,7 +144,7 @@ section. ▼ 🔄 Run deployment hooks ▼ -⑧ 😷 Run DB sanitization +⑨ 😷 Run DB sanitization ▼ ⚙️ Run custom scripts ▼ @@ -164,8 +164,8 @@ You can control the provisioning flow using the following environment variables: 5. `VORTEX_PROVISION_POST_OPERATIONS_SKIP=1`
Skip configuration imports, database updates, and other post-provisioning steps. Essentially, this is `drush sql:drop` and `$(drush sql:connect) < .data/db.sql` commands. This is useful when you want to provision a site without running any additional operations.
`ahoy import-db` uses this flag to import DB and exit.

6. `VORTEX_PROVISION_USE_MAINTENANCE_MODE=1`
Enable maintenance mode right after the site is bootstrappable and disable it at the end. Useful when you want to prevent users from accessing the site while it is being provisioned.

7. `VORTEX_PROVISION_VERIFY_CONFIG_UNCHANGED_AFTER_UPDATE=1`
Verify that active configuration was not changed by database updates. When enabled and config files are present, the provision will fail if `drush updatedb` modifies active configuration, preventing `drush config:import` from silently overwriting those changes.

-8. `VORTEX_PROVISION_SANITIZE_DB_SKIP=1`
Disable database sanitization.

-9. `VORTEX_PROVISION_CACHE_REBUILD_AFTER_DB_UPDATE_SKIP=1`
Skip the cache rebuild that runs between database updates and configuration import. By default, caches are rebuilt after `drush updatedb` to ensure a clean state before importing configuration. +8. `VORTEX_PROVISION_CACHE_REBUILD_AFTER_DB_UPDATE_SKIP=1`
Skip the cache rebuild that runs between database updates and configuration import. By default, caches are rebuilt after `drush updatedb` to ensure a clean state before importing configuration.

+9. `VORTEX_PROVISION_SANITIZE_DB_SKIP=1`
Disable database sanitization. :::tip From f6b8e6bd90e00d2420475910b13d1e19f7cecb7e Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Sat, 21 Mar 2026 23:28:15 +1100 Subject: [PATCH 11/16] Added bats tests for fallback with config files and cache rebuild skip. --- .vortex/tests/bats/unit/provision.bats | 218 +++++++++++++++++++++++++ 1 file changed, 218 insertions(+) diff --git a/.vortex/tests/bats/unit/provision.bats b/.vortex/tests/bats/unit/provision.bats index 9d9acd2dd..a81854970 100644 --- a/.vortex/tests/bats/unit/provision.bats +++ b/.vortex/tests/bats/unit/provision.bats @@ -1639,6 +1639,224 @@ assert_provision_info() { popd >/dev/null || exit 1 } +@test "Provision: DB; no site; fallback to profile; configs" { + pushd "${LOCAL_REPO_DIR}" >/dev/null || exit 1 + + # Remove .env file to test in isolation. + rm ./.env && touch ./.env + rm -f ./scripts/custom/provision-20-migration.sh + + export VORTEX_PROVISION_SANITIZE_DB_PASSWORD="MOCK_DB_SANITIZE_PASSWORD" + export CI=1 + + # Create the data directory but do NOT create the dump file. + mkdir "./.data" + + # Create config files so site_has_config_files=1. + mocked_uuid="c9360453-e1ea-4292-b074-ea375f97d72b" + echo "uuid: ${mocked_uuid}" >"./config/default/system.site.yml" + echo "name: 'SUT'" >>"./config/default/system.site.yml" + + export VORTEX_PROVISION_FALLBACK_TO_PROFILE=1 + export VORTEX_PROVISION_POST_OPERATIONS_SKIP=1 + + create_global_command_wrapper "vendor/bin/drush" + + declare -a STEPS=( + # Drush status calls. + "@drush -y --version # Drush Commandline Tool mocked_drush_version" + "@drush -y status --field=drupal-version # mocked_core_version" + "@drush -y status --fields=bootstrap # fail" + "@drush -y php:eval print realpath(\Drupal\Core\Site\Settings::get(\"config_sync_directory\")); # $(pwd)/config/default" + + # Site provisioning information. + "Provisioning site from the database dump file." + "Dump file path: $(pwd)/.data/db.sql" + "Existing site was not found." + "Fresh site content will be imported from the database dump file." + + # Fallback to profile - should NOT use --existing-config. + "Database dump file is not available. Falling back to profile installation." + "@drush -y sql:drop" + "@drush -y site:install standard --site-name=Example site --site-mail=webmaster@example.com --account-name=admin install_configure_form.enable_update_status_module=NULL install_configure_form.enable_update_status_emails=NULL" + "Installed a site from the profile." + + # Cleanup of profile-created entities and config. + "Removing entities and config created by the profile to prevent conflicts during configuration import." + "@drush -y sql:query DELETE FROM shortcut_set_users" + "@drush -y sql:query DELETE FROM shortcut_field_data" + "@drush -y sql:query DELETE FROM shortcut" + "@drush -y sql:query DELETE FROM config WHERE name LIKE 'shortcut.set.%'" + "@drush -y config:delete field.field.node.article.body" + "@drush -y config:delete field.field.node.article.field_image" + "@drush -y config:delete field.storage.node.field_image" + "@drush -y config:delete taxonomy.vocabulary.tags" + "@drush -y config:delete user.role.content_editor" + + # Should NOT see --existing-config in the site:install command. + "- --existing-config" + + # Should NOT see the hard failure messages. + "- Unable to import database from file." + "- Dump file $(pwd)/.data/db.sql does not exist." + "- Site content was not changed." + + # Drupal environment information. + "Current Drupal environment: ci" + "@drush -y php:eval print \Drupal\core\Site\Settings::get('environment'); # ci" + + # Post-provision operations skipped. + "Skipped running of post-provision operations as VORTEX_PROVISION_POST_OPERATIONS_SKIP is set to 1." + + # Installation completion. + "Finished site provisioning" + ) + + mocks="$(run_steps "setup")" + + run ./scripts/vortex/provision.sh + assert_success + + run_steps "assert" "${mocks[@]}" + + popd >/dev/null || exit 1 +} + +@test "Provision: DB; no site; cache rebuild skip" { + pushd "${LOCAL_REPO_DIR}" >/dev/null || exit 1 + + # Remove .env file to test in isolation. + rm ./.env && touch ./.env + rm -f ./scripts/custom/provision-20-migration.sh + + export VORTEX_PROVISION_SANITIZE_DB_PASSWORD="MOCK_DB_SANITIZE_PASSWORD" + export CI=1 + + mkdir "./.data" + touch "./.data/db.sql" + + export VORTEX_PROVISION_CACHE_REBUILD_AFTER_DB_UPDATE_SKIP=1 + + create_global_command_wrapper "vendor/bin/drush" + + declare -a STEPS=( + # Drush status calls. + "@drush -y --version # Drush Commandline Tool mocked_drush_version" + "@drush -y status --field=drupal-version # mocked_core_version" + "@drush -y status --fields=bootstrap # fail" + "@drush -y php:eval print realpath(\Drupal\Core\Site\Settings::get(\"config_sync_directory\")); # $(pwd)/config/default" + + # Site provisioning information. + "Provisioning site from the database dump file." + "Dump file path: $(pwd)/.data/db.sql" + "Existing site was not found." + "Fresh site content will be imported from the database dump file." + "@drush -y sql:drop" + "@drush -y sql:connect" + "Imported database from the dump file." + # Profile. + "- Provisioning site from the profile." + "- Installed a site from the profile." + + # Drupal environment information. + "Current Drupal environment: ci" + "@drush -y php:eval print \Drupal\core\Site\Settings::get('environment'); # ci" + + # Post-provision operations. + "- Skipped running of post-provision operations as VORTEX_PROVISION_POST_OPERATIONS_SKIP is set to 1." + + # Maintenance mode. + "Enabling maintenance mode." + "@drush -y maint:set 1" + "Enabled maintenance mode." + + # Deployment and configuration updates. + "- Updated site UUID from the configuration with" + "- Importing configuration." + "- Importing config_split configuration." + + # Database updates. + "Running database updates." + "@drush -y updatedb --no-cache-clear" + "Completed running database updates." + + # Cache rebuild after database updates - SKIPPED. + "Skipped cache rebuild after database updates." + "- Clearing cache after database updates." + "- Cache was cleared." + + # Cache rebuild. + "Rebuilding cache." + "@drush -y cache:rebuild" + "Cache was rebuilt." + + # Deployment hooks. + "Running deployment hooks." + "@drush -y deploy:hook" + "Completed deployment hooks." + + # Database sanitization. + "Sanitizing database." + "@drush -y sql:sanitize --sanitize-password=MOCK_DB_SANITIZE_PASSWORD --sanitize-email=user+%uid@localhost" + "Sanitized database using drush sql:sanitize." + "- Updated username with user email." + "@drush -y sql:query --file=../scripts/sanitize.sql" + "Applied custom sanitization commands from file" + "@drush -y sql:query UPDATE \`users_field_data\` SET mail = '', name = '' WHERE uid = '0';" + "@drush -y sql:query UPDATE \`users_field_data\` SET name = '' WHERE uid = '0';" + "Reset user 0 username and email." + "- Updated user 1 email." + "- Skipped database sanitization as VORTEX_PROVISION_SANITIZE_DB_SKIP is set to 1." + + # Custom post-install script. + "Running custom post-install script './scripts/custom/provision-10-example.sh'." + "@drush -y php:eval print \Drupal\core\Site\Settings::get('environment'); # ci" + " > Setting site name." + "@drush -y php:eval \Drupal::service('config.factory')->getEditable('system.site')->set('name', 'YOURSITE')->save();" + " > Installing contrib modules." + "@drush -y pm:install admin_toolbar coffee config_split config_update media environment_indicator pathauto redirect robotstxt shield stage_file_proxy xmlsitemap" + " > Installing Redis module." + "@drush -y pm:install redis" + " > Installing and configuring ClamAV." + "@drush -y pm:install clamav" + "@drush -y config:set clamav.settings mode_daemon_tcpip.hostname clamav --input-format=yaml" + "@drush -y config:set clamav.settings mode_daemon_tcpip.port 3310 --input-format=yaml" + " > Installing and configuring Solr modules." + "@drush -y pm:install search_api search_api_solr" + " > Installing custom modules." + "@drush -y pm:install ys_base" + "@drush -y pm:install ys_search" + "@drush -y pm:install ys_demo" + " > Running deployment hooks." + "@drush -y deploy:hook" + " ==> Started example operations." + " Environment: ci" + " Running example operations in non-production environment." + # Assert that VORTEX_PROVISION_OVERRIDE_DB is correctly passed to the script. + " Fresh database detected. Performing additional example operations." + "- Existing database detected. Performing additional example operations." + " ==> Finished example operations." + "Completed running of custom post-install script './scripts/custom/provision-10-example.sh'." + + # Disabling maintenance mode. + "Disabling maintenance mode." + "@drush -y maint:set 0" + "Disabled maintenance mode." + + # Installation completion. + "Finished site provisioning" + ) + + mocks="$(run_steps "setup")" + + run ./scripts/vortex/provision.sh + assert_success + + run_steps "assert" "${mocks[@]}" + + popd >/dev/null || exit 1 +} + @test "Provision: DB; no site; no fallback" { pushd "${LOCAL_REPO_DIR}" >/dev/null || exit 1 From fc99f7aa5f585bb16faba63c7ae89dd3e0fdc2c2 Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Sat, 21 Mar 2026 23:50:41 +1100 Subject: [PATCH 12/16] Fixed mock commands in cache rebuild skip bats test. --- .vortex/tests/bats/unit/provision.bats | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.vortex/tests/bats/unit/provision.bats b/.vortex/tests/bats/unit/provision.bats index a81854970..20c3400e6 100644 --- a/.vortex/tests/bats/unit/provision.bats +++ b/.vortex/tests/bats/unit/provision.bats @@ -1819,11 +1819,10 @@ assert_provision_info() { "@drush -y pm:install redis" " > Installing and configuring ClamAV." "@drush -y pm:install clamav" - "@drush -y config:set clamav.settings mode_daemon_tcpip.hostname clamav --input-format=yaml" - "@drush -y config:set clamav.settings mode_daemon_tcpip.port 3310 --input-format=yaml" - " > Installing and configuring Solr modules." + "@drush -y config-set clamav.settings mode_daemon_tcpip.hostname clamav" + " > Installing Solr search modules." "@drush -y pm:install search_api search_api_solr" - " > Installing custom modules." + " > Installing custom site modules." "@drush -y pm:install ys_base" "@drush -y pm:install ys_search" "@drush -y pm:install ys_demo" From 10cd4a3a5072d39c4ba16b18ab58aed406771796 Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Sun, 22 Mar 2026 09:43:22 +1100 Subject: [PATCH 13/16] Suppressed output of profile entity cleanup commands. --- scripts/vortex/provision.sh | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/scripts/vortex/provision.sh b/scripts/vortex/provision.sh index a40f69f93..320fc4840 100755 --- a/scripts/vortex/provision.sh +++ b/scripts/vortex/provision.sh @@ -217,15 +217,15 @@ provision_from_profile() { # Use direct SQL to delete shortcut entities to avoid triggering hooks # from modules that are not yet installed (e.g., redirect module's # redirect_delete_by_path() queries a table that does not exist). - drush sql:query "DELETE FROM shortcut_set_users" || true - drush sql:query "DELETE FROM shortcut_field_data" || true - drush sql:query "DELETE FROM shortcut" || true - drush sql:query "DELETE FROM config WHERE name LIKE 'shortcut.set.%'" || true - drush config:delete field.field.node.article.body || true - drush config:delete field.field.node.article.field_image || true - drush config:delete field.storage.node.field_image || true - drush config:delete taxonomy.vocabulary.tags || true - drush config:delete user.role.content_editor || true + drush sql:query "DELETE FROM shortcut_set_users" >/dev/null 2>&1 || true + drush sql:query "DELETE FROM shortcut_field_data" >/dev/null 2>&1 || true + drush sql:query "DELETE FROM shortcut" >/dev/null 2>&1 || true + drush sql:query "DELETE FROM config WHERE name LIKE 'shortcut.set.%'" >/dev/null 2>&1 || true + drush config:delete field.field.node.article.body >/dev/null 2>&1 || true + drush config:delete field.field.node.article.field_image >/dev/null 2>&1 || true + drush config:delete field.storage.node.field_image >/dev/null 2>&1 || true + drush config:delete taxonomy.vocabulary.tags >/dev/null 2>&1 || true + drush config:delete user.role.content_editor >/dev/null 2>&1 || true fi pass "Installed a site from the profile." From 37db8e273c459d91bddb0c9d39c0b674d715976e Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Mon, 23 Mar 2026 10:24:35 +1100 Subject: [PATCH 14/16] Simplified fallback to install from profile, enable Shield, and skip post-provision. --- .vortex/docs/content/drupal/provision.mdx | 2 +- .vortex/tests/bats/unit/provision.bats | 91 +------------------ .../phpunit/Functional/AhoyWorkflowTest.php | 17 +--- scripts/vortex/provision.sh | 20 +--- 4 files changed, 15 insertions(+), 115 deletions(-) diff --git a/.vortex/docs/content/drupal/provision.mdx b/.vortex/docs/content/drupal/provision.mdx index 65e6e56a5..2088ba08d 100644 --- a/.vortex/docs/content/drupal/provision.mdx +++ b/.vortex/docs/content/drupal/provision.mdx @@ -160,7 +160,7 @@ You can control the provisioning flow using the following environment variables: 1. `VORTEX_PROVISION_SKIP=1`
Kill-switch to completely skip provisioning. The script will exit immediately after start. Useful in emergencies when any kind of automation needs to be disabled.

2. `VORTEX_PROVISION_TYPE=profile`
Install from a Drupal `profile` instead of importing from a `database` dump. Useful for building sites without the persistent DB and/or test profile configuration installation.

3. `VORTEX_PROVISION_OVERRIDE_DB=1`
Drop an existing database before importing from dump/installing from profile. This is useful when an already provisioned environment requires a fresh database to be imported.

-4. `VORTEX_PROVISION_FALLBACK_TO_PROFILE=1`
Automatically fall back to installing from profile if the database dump file or container image is not available. When falling back, the `--existing-config` flag is not used during `drush site:install` because profiles with `hook_install()` (like `standard`) cannot be installed from configuration. Any entities created by the profile's `hook_install()` are automatically removed to prevent conflicts during the subsequent configuration import step. Useful for distribution demos or when using recipes/profiles that can install without a pre-existing database.

+4. `VORTEX_PROVISION_FALLBACK_TO_PROFILE=1`
Automatically fall back to installing from profile if the database dump file or container image is not available. The site is installed from the configured profile, the Shield module is enabled to protect the environment, and all post-provision operations (configuration import, database updates, deployment hooks, etc.) are skipped. This provides a minimal working Drupal site when no database is available.

5. `VORTEX_PROVISION_POST_OPERATIONS_SKIP=1`
Skip configuration imports, database updates, and other post-provisioning steps. Essentially, this is `drush sql:drop` and `$(drush sql:connect) < .data/db.sql` commands. This is useful when you want to provision a site without running any additional operations.
`ahoy import-db` uses this flag to import DB and exit.

6. `VORTEX_PROVISION_USE_MAINTENANCE_MODE=1`
Enable maintenance mode right after the site is bootstrappable and disable it at the end. Useful when you want to prevent users from accessing the site while it is being provisioned.

7. `VORTEX_PROVISION_VERIFY_CONFIG_UNCHANGED_AFTER_UPDATE=1`
Verify that active configuration was not changed by database updates. When enabled and config files are present, the provision will fail if `drush updatedb` modifies active configuration, preventing `drush config:import` from silently overwriting those changes.

diff --git a/.vortex/tests/bats/unit/provision.bats b/.vortex/tests/bats/unit/provision.bats index 20c3400e6..b0c091ccf 100644 --- a/.vortex/tests/bats/unit/provision.bats +++ b/.vortex/tests/bats/unit/provision.bats @@ -1526,7 +1526,6 @@ assert_provision_info() { mkdir "./.data" export VORTEX_PROVISION_FALLBACK_TO_PROFILE=1 - export VORTEX_PROVISION_POST_OPERATIONS_SKIP=1 create_global_command_wrapper "vendor/bin/drush" @@ -1543,10 +1542,11 @@ assert_provision_info() { "Existing site was not found." "Fresh site content will be imported from the database dump file." - # Fallback to profile. + # Fallback to profile: install and enable Shield. "Database dump file is not available. Falling back to profile installation." "@drush -y sql:drop" "@drush -y site:install standard --site-name=Example site --site-mail=webmaster@example.com --account-name=admin install_configure_form.enable_update_status_module=NULL install_configure_form.enable_update_status_emails=NULL" + "@drush -y pm:install shield" "Installed a site from the profile." # Should NOT see the hard failure messages. @@ -1558,7 +1558,7 @@ assert_provision_info() { "Current Drupal environment: ci" "@drush -y php:eval print \Drupal\core\Site\Settings::get('environment'); # ci" - # Post-provision operations skipped. + # Post-provision operations skipped (set internally by fallback). "Skipped running of post-provision operations as VORTEX_PROVISION_POST_OPERATIONS_SKIP is set to 1." # Installation completion. @@ -1589,7 +1589,6 @@ assert_provision_info() { touch "./.data/db.sql" export VORTEX_PROVISION_FALLBACK_TO_PROFILE=1 - export VORTEX_PROVISION_POST_OPERATIONS_SKIP=1 create_global_command_wrapper "vendor/bin/drush" @@ -1611,6 +1610,7 @@ assert_provision_info() { "Database in the container image is not available. Falling back to profile installation." "@drush -y sql:drop" "@drush -y site:install standard --site-name=Example site --site-mail=webmaster@example.com --account-name=admin install_configure_form.enable_update_status_module=NULL install_configure_form.enable_update_status_emails=NULL" + "@drush -y pm:install shield" "Installed a site from the profile." # Should NOT see the corrupted error messages or file-based provisioning. @@ -1639,89 +1639,6 @@ assert_provision_info() { popd >/dev/null || exit 1 } -@test "Provision: DB; no site; fallback to profile; configs" { - pushd "${LOCAL_REPO_DIR}" >/dev/null || exit 1 - - # Remove .env file to test in isolation. - rm ./.env && touch ./.env - rm -f ./scripts/custom/provision-20-migration.sh - - export VORTEX_PROVISION_SANITIZE_DB_PASSWORD="MOCK_DB_SANITIZE_PASSWORD" - export CI=1 - - # Create the data directory but do NOT create the dump file. - mkdir "./.data" - - # Create config files so site_has_config_files=1. - mocked_uuid="c9360453-e1ea-4292-b074-ea375f97d72b" - echo "uuid: ${mocked_uuid}" >"./config/default/system.site.yml" - echo "name: 'SUT'" >>"./config/default/system.site.yml" - - export VORTEX_PROVISION_FALLBACK_TO_PROFILE=1 - export VORTEX_PROVISION_POST_OPERATIONS_SKIP=1 - - create_global_command_wrapper "vendor/bin/drush" - - declare -a STEPS=( - # Drush status calls. - "@drush -y --version # Drush Commandline Tool mocked_drush_version" - "@drush -y status --field=drupal-version # mocked_core_version" - "@drush -y status --fields=bootstrap # fail" - "@drush -y php:eval print realpath(\Drupal\Core\Site\Settings::get(\"config_sync_directory\")); # $(pwd)/config/default" - - # Site provisioning information. - "Provisioning site from the database dump file." - "Dump file path: $(pwd)/.data/db.sql" - "Existing site was not found." - "Fresh site content will be imported from the database dump file." - - # Fallback to profile - should NOT use --existing-config. - "Database dump file is not available. Falling back to profile installation." - "@drush -y sql:drop" - "@drush -y site:install standard --site-name=Example site --site-mail=webmaster@example.com --account-name=admin install_configure_form.enable_update_status_module=NULL install_configure_form.enable_update_status_emails=NULL" - "Installed a site from the profile." - - # Cleanup of profile-created entities and config. - "Removing entities and config created by the profile to prevent conflicts during configuration import." - "@drush -y sql:query DELETE FROM shortcut_set_users" - "@drush -y sql:query DELETE FROM shortcut_field_data" - "@drush -y sql:query DELETE FROM shortcut" - "@drush -y sql:query DELETE FROM config WHERE name LIKE 'shortcut.set.%'" - "@drush -y config:delete field.field.node.article.body" - "@drush -y config:delete field.field.node.article.field_image" - "@drush -y config:delete field.storage.node.field_image" - "@drush -y config:delete taxonomy.vocabulary.tags" - "@drush -y config:delete user.role.content_editor" - - # Should NOT see --existing-config in the site:install command. - "- --existing-config" - - # Should NOT see the hard failure messages. - "- Unable to import database from file." - "- Dump file $(pwd)/.data/db.sql does not exist." - "- Site content was not changed." - - # Drupal environment information. - "Current Drupal environment: ci" - "@drush -y php:eval print \Drupal\core\Site\Settings::get('environment'); # ci" - - # Post-provision operations skipped. - "Skipped running of post-provision operations as VORTEX_PROVISION_POST_OPERATIONS_SKIP is set to 1." - - # Installation completion. - "Finished site provisioning" - ) - - mocks="$(run_steps "setup")" - - run ./scripts/vortex/provision.sh - assert_success - - run_steps "assert" "${mocks[@]}" - - popd >/dev/null || exit 1 -} - @test "Provision: DB; no site; cache rebuild skip" { pushd "${LOCAL_REPO_DIR}" >/dev/null || exit 1 diff --git a/.vortex/tests/phpunit/Functional/AhoyWorkflowTest.php b/.vortex/tests/phpunit/Functional/AhoyWorkflowTest.php index a042d85b8..b8bfd775b 100644 --- a/.vortex/tests/phpunit/Functional/AhoyWorkflowTest.php +++ b/.vortex/tests/phpunit/Functional/AhoyWorkflowTest.php @@ -484,23 +484,16 @@ public function testAhoyWorkflowProvisionFallbackToProfile(): void { [ '* Database dump file is not available. Falling back to profile installation', '* Installed a site from the profile', - '* Removing entities and config created by the profile to prevent conflicts during configuration import', - '* Importing configuration', - '* Completed configuration import', - '* Running deployment hooks', + '* Skipped running of post-provision operations', + '! Importing configuration', + '! Running deployment hooks', ], 'Provision with fallback should complete successfully', tio: 15 * 60, ); - $this->logSubstep('Assert that required modules are enabled'); - $this->cmd('ahoy drush pm:list --status=enabled --type=module --format=list', '* sw_demo', 'Demo module should be enabled after fallback provision'); - - $this->logSubstep('Assert that homepage does not contain database dump content'); - $this->assertWebpageNotContains('/', 'This demo page is sourced from the Vortex database dump file', 'Homepage should not show database dump content after fallback provision'); - - $this->logSubstep('Assert that homepage is accessible'); - $this->assertWebpageContains('/', 'logSubstep('Assert that Shield module is enabled'); + $this->cmd('ahoy drush pm:list --status=enabled --type=module --format=list', '* shield', 'Shield module should be enabled after fallback provision'); } } diff --git a/scripts/vortex/provision.sh b/scripts/vortex/provision.sh index 320fc4840..9e508d2fa 100755 --- a/scripts/vortex/provision.sh +++ b/scripts/vortex/provision.sh @@ -204,7 +204,6 @@ provision_from_profile() { [ -n "${DRUPAL_ADMIN_EMAIL:-}" ] && opts+=(--account-mail="${DRUPAL_ADMIN_EMAIL:-}") - # Only use --existing-config for direct profile provisions. [ "${is_fallback}" != "1" ] && [ "${has_config}" = "1" ] && opts+=(--existing-config) # Database may exist in non-bootstrappable state - truncate it. @@ -212,20 +211,11 @@ provision_from_profile() { drush site:install "${opts[@]}" - if [ "${is_fallback}" = "1" ] && [ "${has_config}" = "1" ]; then - note "Removing entities and config created by the profile to prevent conflicts during configuration import." - # Use direct SQL to delete shortcut entities to avoid triggering hooks - # from modules that are not yet installed (e.g., redirect module's - # redirect_delete_by_path() queries a table that does not exist). - drush sql:query "DELETE FROM shortcut_set_users" >/dev/null 2>&1 || true - drush sql:query "DELETE FROM shortcut_field_data" >/dev/null 2>&1 || true - drush sql:query "DELETE FROM shortcut" >/dev/null 2>&1 || true - drush sql:query "DELETE FROM config WHERE name LIKE 'shortcut.set.%'" >/dev/null 2>&1 || true - drush config:delete field.field.node.article.body >/dev/null 2>&1 || true - drush config:delete field.field.node.article.field_image >/dev/null 2>&1 || true - drush config:delete field.storage.node.field_image >/dev/null 2>&1 || true - drush config:delete taxonomy.vocabulary.tags >/dev/null 2>&1 || true - drush config:delete user.role.content_editor >/dev/null 2>&1 || true + # On fallback, enable Shield to protect the site and skip post-provision + # operations since the site was installed from profile without configuration. + if [ "${is_fallback}" = "1" ]; then + drush pm:install shield + export VORTEX_PROVISION_POST_OPERATIONS_SKIP=1 fi pass "Installed a site from the profile." From 0b8041544884479639a12a7162a4de490ad9492d Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Mon, 23 Mar 2026 10:33:21 +1100 Subject: [PATCH 15/16] Restored homepage and module assertions in fallback functional test. --- .vortex/tests/phpunit/Functional/AhoyWorkflowTest.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.vortex/tests/phpunit/Functional/AhoyWorkflowTest.php b/.vortex/tests/phpunit/Functional/AhoyWorkflowTest.php index b8bfd775b..3df55e1c7 100644 --- a/.vortex/tests/phpunit/Functional/AhoyWorkflowTest.php +++ b/.vortex/tests/phpunit/Functional/AhoyWorkflowTest.php @@ -494,6 +494,15 @@ public function testAhoyWorkflowProvisionFallbackToProfile(): void { $this->logSubstep('Assert that Shield module is enabled'); $this->cmd('ahoy drush pm:list --status=enabled --type=module --format=list', '* shield', 'Shield module should be enabled after fallback provision'); + + $this->logSubstep('Assert that demo module is not enabled'); + $this->cmd('ahoy drush pm:list --status=enabled --type=module --format=list', '! sw_demo', 'Demo module should not be enabled after fallback provision'); + + $this->logSubstep('Assert that homepage does not contain database dump content'); + $this->assertWebpageNotContains('/', 'This demo page is sourced from the Vortex database dump file', 'Homepage should not show database dump content after fallback provision'); + + $this->logSubstep('Assert that homepage is accessible'); + $this->assertWebpageContains('/', ' Date: Mon, 23 Mar 2026 10:58:25 +1100 Subject: [PATCH 16/16] Removed unreliable 'sw_demo' module assertion from fallback test. --- .vortex/tests/phpunit/Functional/AhoyWorkflowTest.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/.vortex/tests/phpunit/Functional/AhoyWorkflowTest.php b/.vortex/tests/phpunit/Functional/AhoyWorkflowTest.php index 3df55e1c7..26d79756a 100644 --- a/.vortex/tests/phpunit/Functional/AhoyWorkflowTest.php +++ b/.vortex/tests/phpunit/Functional/AhoyWorkflowTest.php @@ -495,9 +495,6 @@ public function testAhoyWorkflowProvisionFallbackToProfile(): void { $this->logSubstep('Assert that Shield module is enabled'); $this->cmd('ahoy drush pm:list --status=enabled --type=module --format=list', '* shield', 'Shield module should be enabled after fallback provision'); - $this->logSubstep('Assert that demo module is not enabled'); - $this->cmd('ahoy drush pm:list --status=enabled --type=module --format=list', '! sw_demo', 'Demo module should not be enabled after fallback provision'); - $this->logSubstep('Assert that homepage does not contain database dump content'); $this->assertWebpageNotContains('/', 'This demo page is sourced from the Vortex database dump file', 'Homepage should not show database dump content after fallback provision');