Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ web/sites/simpletest
# Composer installs contrib recipes into 'recipes/', next to custom recipes,
# so recipes stay an allow list: un-ignore custom recipes explicitly.
recipes/*
#;< CONTENT_MODEL
!recipes/page
#;> CONTENT_MODEL

#;< AI_CODE_INSTRUCTIONS
# Ignore all Claude files by default. Custom files should be added explicitly.
Expand Down
1 change: 1 addition & 0 deletions .vortex/installer/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ Content removed if feature not selected
| Category | Tokens |
|----------|------------------------------------------------------------------------------------|
| Theme | `DRUPAL_THEME` |
| Content | `CONTENT_MODEL` - the starter 'page' content model, kept while the demo or the search custom module is selected |
| Services | `SERVICE_ANTIVIRUS`, `SERVICE_SEARCH`, `SERVICE_CACHE` |
| CI | `CI_PROVIDER_GHA`, `CI_PROVIDER_CIRCLECI` |
| Hosting | `HOSTING_LAGOON`, `HOSTING_ACQUIA` |
Expand Down
73 changes: 42 additions & 31 deletions .vortex/installer/src/Prompts/Handlers/CustomModules.php
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,6 @@ public function discover(): null|string|bool|array {
public function process(): void {
$selected = $this->getResponseAsArray();
$t = $this->tmpDir;
$w = $this->webroot;

// Safety net: if search was selected but Solr service was not, force-remove
// search module since it cannot function without Solr.
Expand All @@ -130,16 +129,7 @@ public function process(): void {
if (!in_array(self::BASE, $selected)) {
File::removeTokenAsync('CUSTOM_MODULE_BASE');

$locations = [
$t . sprintf('/%s/modules/custom/*_base', $w),
$t . sprintf('/%s/sites/all/modules/custom/*_base', $w),
$t . sprintf('/%s/profiles/*/modules/*_base', $w),
$t . sprintf('/%s/profiles/*/modules/custom/*_base', $w),
$t . sprintf('/%s/profiles/custom/*/modules/*_base', $w),
$t . sprintf('/%s/profiles/custom/*/modules/custom/*_base', $w),
];

$path = File::findMatchingPath($locations);
$path = File::findMatchingPath($this->moduleLocations('base'));
if ($path) {
File::remove($path);
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Expand All @@ -148,16 +138,7 @@ public function process(): void {
if (!in_array(self::DEMO, $selected)) {
File::removeTokenAsync('CUSTOM_MODULE_DEMO');

$locations = [
$t . sprintf('/%s/modules/custom/*_demo', $w),
$t . sprintf('/%s/sites/all/modules/custom/*_demo', $w),
$t . sprintf('/%s/profiles/*/modules/*_demo', $w),
$t . sprintf('/%s/profiles/*/modules/custom/*_demo', $w),
$t . sprintf('/%s/profiles/custom/*/modules/*_demo', $w),
$t . sprintf('/%s/profiles/custom/*/modules/custom/*_demo', $w),
];

$path = File::findMatchingPath($locations);
$path = File::findMatchingPath($this->moduleLocations('demo'));
if ($path) {
File::remove($path);
}
Expand All @@ -168,20 +149,50 @@ public function process(): void {
if (!in_array(self::SEARCH, $selected)) {
File::removeTokenAsync('CUSTOM_MODULE_SEARCH');

$locations = [
$t . sprintf('/%s/modules/custom/*_search', $w),
$t . sprintf('/%s/sites/all/modules/custom/*_search', $w),
$t . sprintf('/%s/profiles/*/modules/*_search', $w),
$t . sprintf('/%s/profiles/*/modules/custom/*_search', $w),
$t . sprintf('/%s/profiles/custom/*/modules/*_search', $w),
$t . sprintf('/%s/profiles/custom/*/modules/custom/*_search', $w),
];

$path = File::findMatchingPath($locations);
$path = File::findMatchingPath($this->moduleLocations('search'));
if ($path) {
File::remove($path);
}
}

// The 'page' content model is the bundle that both the demo content and the
// search example content are built on, so it only becomes dead weight once
// neither of those modules is selected. Runs after the base module removal
// above so the deploy step is already gone with its module when base was
// deselected.
if (!in_array(self::DEMO, $selected) && !in_array(self::SEARCH, $selected)) {
File::removeTokenAsync('CONTENT_MODEL');

File::remove($t . '/recipes/page');

$path = File::findMatchingPath($this->moduleLocations('base'));
if ($path) {
File::remove($path . '/src/Plugin/DeployStep/CreateContentModelDeployStep.php');
}
}
}

/**
* Get the locations a custom module with the given suffix can live in.
*
* @param string $suffix
* The module name suffix, without the leading underscore.
*
* @return array<int, string>
* Array of glob patterns, ordered from the most to the least common.
*/
protected function moduleLocations(string $suffix): array {
$t = $this->tmpDir;
$w = $this->webroot;

return [
$t . sprintf('/%s/modules/custom/*_%s', $w, $suffix),
$t . sprintf('/%s/sites/all/modules/custom/*_%s', $w, $suffix),
$t . sprintf('/%s/profiles/*/modules/*_%s', $w, $suffix),
$t . sprintf('/%s/profiles/*/modules/custom/*_%s', $w, $suffix),
$t . sprintf('/%s/profiles/custom/*/modules/*_%s', $w, $suffix),
$t . sprintf('/%s/profiles/custom/*/modules/custom/*_%s', $w, $suffix),
];
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,12 @@
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
* Creates the demo content model on non-production deploys.
* Creates the starter content model on non-production deploys.
*
* Applies the project 'page' recipe so the Basic page content type, its body
* field and displays exist before the demo modules that attach behaviour to
* that type are installed. Runs ahead of EnableDevelopmentModulesDeployStep in
* the PRE phase (lower weight) for that reason. Idempotent - the step skips
* once the content type exists - so it is safe on every deploy.
* field and displays exist before any module that attaches behaviour to that
* type is installed - hence the lowest weight in the PRE phase. Idempotent -
* the step skips once the content type exists - so it is safe on every deploy.
*
* @codeCoverageIgnore
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
@@ -32,7 +32,6 @@
# Composer installs contrib recipes into 'recipes/', next to custom recipes,
# so recipes stay an allow list: un-ignore custom recipes explicitly.
recipes/*
-!recipes/page

# Ignore all Claude files by default. Custom files should be added explicitly.
.claude/*
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
@@ -104,9 +104,6 @@

$this->moduleInstaller->install(['devel']);

- $this->moduleInstaller->install(['sw_search']);
-
- $this->moduleInstaller->install(['sw_demo']);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
@@ -32,7 +32,6 @@
# Composer installs contrib recipes into 'recipes/', next to custom recipes,
# so recipes stay an allow list: un-ignore custom recipes explicitly.
recipes/*
-!recipes/page

# Ignore all Claude files by default. Custom files should be added explicitly.
.claude/*
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,12 @@
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
* Creates the demo content model on non-production deploys.
* Creates the starter content model on non-production deploys.
*
* Applies the project 'page' recipe so the Basic page content type, its body
* field and displays exist before the demo modules that attach behaviour to
* that type are installed. Runs ahead of EnableDevelopmentModulesDeployStep in
* the PRE phase (lower weight) for that reason. Idempotent - the step skips
* once the content type exists - so it is safe on every deploy.
* field and displays exist before any module that attaches behaviour to that
* type is installed - hence the lowest weight in the PRE phase. Idempotent -
* the step skips once the content type exists - so it is safe on every deploy.
*
* @codeCoverageIgnore
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,12 @@
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
* Creates the demo content model on non-production deploys.
* Creates the starter content model on non-production deploys.
*
* Applies the project 'page' recipe so the Basic page content type, its body
* field and displays exist before the demo modules that attach behaviour to
* that type are installed. Runs ahead of EnableDevelopmentModulesDeployStep in
* the PRE phase (lower weight) for that reason. Idempotent - the step skips
* once the content type exists - so it is safe on every deploy.
* field and displays exist before any module that attaches behaviour to that
* type is installed - hence the lowest weight in the PRE phase. Idempotent -
* the step skips once the content type exists - so it is safe on every deploy.
*
* @codeCoverageIgnore
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,12 @@
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
* Creates the demo content model on non-production deploys.
* Creates the starter content model on non-production deploys.
*
* Applies the project 'page' recipe so the Basic page content type, its body
* field and displays exist before the demo modules that attach behaviour to
* that type are installed. Runs ahead of EnableDevelopmentModulesDeployStep in
* the PRE phase (lower weight) for that reason. Idempotent - the step skips
* once the content type exists - so it is safe on every deploy.
* field and displays exist before any module that attaches behaviour to that
* type is installed - hence the lowest weight in the PRE phase. Idempotent -
* the step skips once the content type exists - so it is safe on every deploy.
*
* @codeCoverageIgnore
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,24 @@ public static function dataProviderHandlerProcess(): \Iterator {
static::cw(function (AbstractHandlerProcessTestCase $test): void {
$test->assertSutNotContains('_demo');
$test->assertSutNotContains('counter_block');
// The search module indexes and moderates the 'page' bundle, so the
// content model stays when only the demo module is dropped.
$test->assertDirectoryExists(static::$sut . '/recipes/page');
$test->assertFileExists(static::$sut . '/web/modules/custom/sw_base/src/Plugin/DeployStep/CreateContentModelDeployStep.php');
}),
];
yield 'custom_modules_base_only' => [
static::cw(function ($test): void {
$test->prompts[CustomModules::id()] = [CustomModules::BASE];
$test->prompts[AiCodeInstructions::id()] = TRUE;
}),
static::cw(function (AbstractHandlerProcessTestCase $test): void {
$test->assertSutNotContains('_demo');
$test->assertSutNotContains('_search');
$test->assertDirectoryExists(static::$sut . '/web/modules/custom/sw_base');
$test->assertDirectoryDoesNotExist(static::$sut . '/recipes/page');
$test->assertFileDoesNotExist(static::$sut . '/web/modules/custom/sw_base/src/Plugin/DeployStep/CreateContentModelDeployStep.php');
$test->assertFileNotContainsString(static::$sut . '/.gitignore', '!recipes/page');
}),
];
yield 'custom_modules_no_search' => [
Expand All @@ -44,6 +62,8 @@ public static function dataProviderHandlerProcess(): \Iterator {
$test->assertSutNotContains('_base');
$test->assertSutNotContains('_demo');
$test->assertSutNotContains('_search');
$test->assertDirectoryDoesNotExist(static::$sut . '/recipes/page');
$test->assertFileNotContainsString(static::$sut . '/.gitignore', '!recipes/page');
}),
];
yield 'custom_modules_search_without_solr' => [
Expand Down
5 changes: 5 additions & 0 deletions .vortex/tests/phpunit/Traits/SutTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,7 @@ protected function assertDrupalFilesPresent(string $webroot = 'web'): void {
$this->assertFileExists($webroot . '/modules/custom/sw_base/sw_base.deploy.php');
$this->assertFileExists($webroot . '/modules/custom/sw_base/sw_base.info.yml');
$this->assertFileExists($webroot . '/modules/custom/sw_base/sw_base.module');
$this->assertFileExists($webroot . '/modules/custom/sw_base/src/Plugin/DeployStep/CreateContentModelDeployStep.php');
$this->assertFileExists($webroot . '/modules/custom/sw_base/src/Plugin/DeployStep/EnableDevelopmentModulesDeployStep.php');
$this->assertFileExists($webroot . '/modules/custom/sw_base/tests/src/Functional/ExampleTest.php');
$this->assertFileExists($webroot . '/modules/custom/sw_base/tests/src/Functional/SwBaseFunctionalTestBase.php');
Expand All @@ -569,6 +570,10 @@ protected function assertDrupalFilesPresent(string $webroot = 'web'): void {
$this->assertFileExists($webroot . '/modules/custom/sw_base/tests/src/Unit/ExampleTest.php');
$this->assertFileExists($webroot . '/modules/custom/sw_base/tests/src/Unit/SwBaseUnitTestBase.php');

// Starter content model recipe applied by the base module's deploy step.
$this->assertFileExists('recipes/page/recipe.yml');
$this->assertFileContainsString('.gitignore', '!recipes/page');

// Site search module created.
$this->assertDirectoryExists($webroot . '/modules/custom/sw_search');
$this->assertFileExists($webroot . '/modules/custom/sw_search/sw_search.info.yml');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,12 @@
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
* Creates the demo content model on non-production deploys.
* Creates the starter content model on non-production deploys.
*
* Applies the project 'page' recipe so the Basic page content type, its body
* field and displays exist before the demo modules that attach behaviour to
* that type are installed. Runs ahead of EnableDevelopmentModulesDeployStep in
* the PRE phase (lower weight) for that reason. Idempotent - the step skips
* once the content type exists - so it is safe on every deploy.
* field and displays exist before any module that attaches behaviour to that
* type is installed - hence the lowest weight in the PRE phase. Idempotent -
* the step skips once the content type exists - so it is safe on every deploy.
*
* @codeCoverageIgnore
*/
Expand Down