-
-
Notifications
You must be signed in to change notification settings - Fork 28
[#1882] Added support for DrupalCMS. #1955
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
WalkthroughAdds Drupal CMS installation support: new Starter options and composer mutation for Drupal CMS; introduces resolveOrPrompt flow and updated HandlerInterface/handlers (Profile, Webroot) with resolvedMessage signature change and Profile resolution API. Adds recipes installer-path, ignores recipes by default, test coverage (unit, functional, bats, Behat), PHPMD exclusion, and CI matrix updates. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant PM as PromptManager
participant H_Profile as Handler: Profile
participant H_Starter as Handler: Starter
participant Env as .env / FS
participant Composer as composer.json
rect rgb(245,248,255)
note over PM: Centralized resolve-or-prompt
User->>PM: Run installer
PM->>H_Profile: resolvedValue(responses)
alt Resolved string
H_Profile-->>PM: "<profile_path>"
PM->>H_Profile: resolvedMessage(responses, "<profile_path>")
H_Profile-->>PM: "Profile will be set to ..."
PM->>User: info(message)
PM-->>User: use "<profile_path>"
else Unresolved
PM-->>User: prompt for profile
end
end
rect rgb(240,255,245)
note over H_Starter: Starter selection
PM->>H_Starter: resolvedValue/resolvedMessage (via resolveOrPrompt)
alt INSTALL_PROFILE_DRUPALCMS selected
PM->>Composer: add drupal/cms, merge-plugin, allow plugins, merge config
PM->>Env: set DRUPAL_PROFILE="../recipes/drupal_cms_starter"
PM->>Env: set VORTEX_PROVISION_TYPE=profile
else INSTALL_PROFILE_CORE or LOAD_DATABASE_DEMO
PM->>Env: set values accordingly
end
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Assessment against linked issues
Assessment against linked issues: Out-of-scope changes
Possibly related PRs
Suggested labels
Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: ASSERTIVE Plan: Pro 💡 Knowledge Base configuration:
You can enable these sources in your CodeRabbit configuration. 📒 Files selected for processing (2)
🧰 Additional context used🧠 Learnings (1)📚 Learning: 2025-08-08T12:02:24.652ZApplied to files:
🧬 Code graph analysis (1).vortex/tests/test.workflow.sh (3)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (14)
🔇 Additional comments (2)
✨ Finishing Touches
🧪 Generate unit tests
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 11
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
.gitignore (1)
34-46: Add defensive ignore for web/recipes and confirm dev workflow expectations.
- Text tweak to “Allow Drupal Scaffold files” looks good.
- To avoid surprises if anyone maps recipes under web/, ignore that location too.
- If teams ever need to commit a seed/custom recipe, document an explicit unignore pattern.
# Ignore all recipes by default. Custom recipes should be added explicitly. recipes/* +web/recipes/*.vortex/installer/src/Prompts/Handlers/Starter.php (1)
131-138: Use strict comparison and simplify condition.Small readability/consistency win.
- elseif ($this->response == self::DRUPAL_INSTALL_PROFILE || $this->response == self::DRUPALCMS_INSTALL_PROFILE) { + elseif (in_array($this->response, [self::DRUPAL_INSTALL_PROFILE, self::DRUPALCMS_INSTALL_PROFILE], true)) {
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (9)
.vortex/installer/tests/Fixtures/install/_baseline/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/_baseline/composer.jsonis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/_baseline/tests/behat/features/search.featureis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/_baseline/web/modules/custom/sw_search/config/install/search_api.index.content.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/_baseline/web/modules/custom/sw_search/config/install/views.view.search.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/starter_demo_db/.ignorecontentis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/starter_drupal_profile/.envis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/starter_drupalcms_profile/.envis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/starter_drupalcms_profile/composer.jsonis excluded by!.vortex/installer/tests/Fixtures/**
📒 Files selected for processing (16)
.gitignore(2 hunks).gitignore.artifact(1 hunks).vortex/installer/src/Prompts/Handlers/AbstractHandler.php(1 hunks).vortex/installer/src/Prompts/Handlers/HandlerInterface.php(1 hunks).vortex/installer/src/Prompts/Handlers/Profile.php(2 hunks).vortex/installer/src/Prompts/Handlers/Starter.php(6 hunks).vortex/installer/src/Prompts/Handlers/Webroot.php(1 hunks).vortex/installer/src/Prompts/PromptManager.php(2 hunks).vortex/installer/tests/Functional/Handlers/StarterInstallTest.php(1 hunks).vortex/installer/tests/Unit/Handlers/StarterPromptManagerTest.php(1 hunks).vortex/tests/bats/_helper.bash(0 hunks).vortex/tests/bats/e2e/workflow.install.profile.bats(1 hunks)composer.json(1 hunks)tests/behat/features/search.feature(1 hunks)web/modules/custom/ys_search/config/install/search_api.index.content.yml(1 hunks)web/modules/custom/ys_search/config/install/views.view.search.yml(1 hunks)
💤 Files with no reviewable changes (1)
- .vortex/tests/bats/_helper.bash
🧰 Additional context used
📓 Path-based instructions (3)
composer.json
📄 CodeRabbit inference engine (CLAUDE.md)
When adding JavaScript or CSS libraries as Drupal libraries with Composer, define them as inline Composer packages in the 'repositories' section of composer.json
Files:
composer.json
tests/behat/**/*.feature
📄 CodeRabbit inference engine (CLAUDE.md)
tests/behat/**/*.feature: All Behat feature files must use the standard user story format: 'As a [user type]\nI want to [action]\nSo that [benefit]'
Use consistent user types in Behat feature files: 'site visitor', 'site administrator', and 'content editor'
Do not use commas or periods in user story statements within Behat feature files
Files:
tests/behat/features/search.feature
web/modules/custom/**
📄 CodeRabbit inference engine (CLAUDE.md)
Custom modules should be placed in 'web/modules/custom/'
Files:
web/modules/custom/ys_search/config/install/views.view.search.ymlweb/modules/custom/ys_search/config/install/search_api.index.content.yml
🧬 Code graph analysis (9)
.vortex/installer/src/Prompts/Handlers/Webroot.php (3)
.vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
resolvedMessage(137-139).vortex/installer/src/Prompts/Handlers/HandlerInterface.php (1)
resolvedMessage(155-155).vortex/installer/src/Prompts/Handlers/Profile.php (1)
resolvedMessage(93-99)
.vortex/installer/tests/Unit/Handlers/StarterPromptManagerTest.php (3)
.vortex/installer/src/Prompts/Handlers/Starter.php (1)
Starter(10-148).vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
id(52-62).vortex/installer/src/Prompts/Handlers/HandlerInterface.php (1)
id(19-19)
.vortex/installer/tests/Functional/Handlers/StarterInstallTest.php (5)
.vortex/installer/src/Prompts/Handlers/ProvisionType.php (1)
ProvisionType(11-103).vortex/installer/src/Prompts/Handlers/Starter.php (1)
Starter(10-148).vortex/installer/src/Prompts/PromptManager.php (2)
PromptManager(58-581)makeEnvName(431-433).vortex/installer/src/Utils/Env.php (2)
Env(7-245)put(24-26).vortex/installer/tests/Functional/Handlers/AbstractInstallTestCase.php (1)
AbstractInstallTestCase(19-101)
.vortex/installer/src/Prompts/Handlers/AbstractHandler.php (3)
.vortex/installer/src/Prompts/Handlers/HandlerInterface.php (1)
resolvedMessage(155-155).vortex/installer/src/Prompts/Handlers/Profile.php (1)
resolvedMessage(93-99).vortex/installer/src/Prompts/Handlers/Webroot.php (1)
resolvedMessage(115-121)
.vortex/tests/bats/e2e/workflow.install.profile.bats (2)
.vortex/tests/bats/_helper.workflow.bash (6)
prepare_sut(7-39)assert_ahoy_build(73-130)assert_gitignore(132-162)assert_ahoy_lint(413-425)assert_ahoy_test(527-544)assert_ahoy_fe(753-777).vortex/tests/bats/_helper.bash (1)
assert_webpage_contains(1022-1028)
.vortex/installer/src/Prompts/Handlers/HandlerInterface.php (3)
.vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
resolvedMessage(137-139).vortex/installer/src/Prompts/Handlers/Profile.php (1)
resolvedMessage(93-99).vortex/installer/src/Prompts/Handlers/Webroot.php (1)
resolvedMessage(115-121)
.vortex/installer/src/Prompts/PromptManager.php (3)
.vortex/installer/src/Prompts/Handlers/Profile.php (3)
Profile(10-165)resolvedValue(76-88)resolvedMessage(93-99).vortex/installer/src/Prompts/Handlers/Webroot.php (2)
resolvedValue(98-110)resolvedMessage(115-121).vortex/installer/src/Utils/Tui.php (1)
info(42-44)
.vortex/installer/src/Prompts/Handlers/Starter.php (2)
.vortex/installer/src/Utils/JsonManipulator.php (2)
JsonManipulator(10-76)fromFile(19-36).vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
AbstractHandler(10-233)
.vortex/installer/src/Prompts/Handlers/Profile.php (5)
.vortex/installer/src/Prompts/Handlers/AbstractHandler.php (4)
resolvedValue(130-132)id(52-62)resolvedMessage(137-139)getResponseAsString(191-197).vortex/installer/src/Prompts/Handlers/HandlerInterface.php (3)
resolvedValue(138-138)id(19-19)resolvedMessage(155-155).vortex/installer/src/Prompts/Handlers/Webroot.php (4)
resolvedValue(98-110)discover(65-79)resolvedMessage(115-121)process(126-146).vortex/installer/src/Prompts/Handlers/Starter.php (1)
Starter(10-148).vortex/installer/src/Utils/File.php (2)
File(10-102)replaceContentAsync(59-83)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (12)
- GitHub Check: build (0)
- GitHub Check: build (1)
- GitHub Check: vortex-test-workflow (2)
- GitHub Check: vortex-test-workflow (1)
- GitHub Check: vortex-test-workflow (3)
- GitHub Check: vortex-test-deployment (1)
- GitHub Check: vortex-test-workflow (0)
- GitHub Check: vortex-test-common
- GitHub Check: vortex-test-deployment (0)
- GitHub Check: vortex-test-installer (8.4)
- GitHub Check: vortex-test-installer (8.3)
- GitHub Check: vortex-test-installer (8.2)
🔇 Additional comments (14)
tests/behat/features/search.feature (4)
11-18: Confirm step supports moderation_state and indexing of unpublished content.
- Ensure the “Given page content:” step accepts moderation_state and status together and sets them correctly.
- Verify the index is expected to include 3 items even if one is draft/unpublished; the view assertions rely on runtime filtering.
20-21: Good move: navigate after the indexing wait.Prevents racing the indexer.
25-27: Assertions for published vs draft visibility look correct.Matches moderation-aware behavior.
31-33: Follow-up query assertions look correct.Ensures only the matching published item is returned.
web/modules/custom/ys_search/config/install/views.view.search.yml (2)
165-202: Good: enforce published-only results via status filter.Non-exposed, fixed status=1 filter is correct and consistent with the index change. No issues.
210-210: Verify teaser availability across bundles.Setting ':default' to teaser is fine for nodes; confirm all indexed bundles have a teaser display or acceptable fallback to avoid sparse result rendering.
.vortex/installer/tests/Unit/Handlers/StarterPromptManagerTest.php (1)
23-30: Tests cover new DrupalCMS option and correct navigation.Keys reflect the options order and default (demo DB). This guards regressions in prompt ordering.
.vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
137-139: Public API change: resolvedMessage signature updated—verify all handler implementations and invocations pass the new $resolved parameter..vortex/installer/tests/Functional/Handlers/StarterInstallTest.php (1)
16-29: Good coverage of the three Starter flows.Scenarios for demo DB, Drupal profile, and DrupalCMS profile are well represented. No functional issues spotted.
.vortex/tests/bats/e2e/workflow.install.profile.bats (1)
32-61: LGTM: DrupalCMS profile e2e path exercises key expectations.Selecting drupalcms_profile, asserting DRUPAL_PROFILE, composer additions, full build/test/FE, and homepage smoke check look solid.
.vortex/installer/src/Prompts/Handlers/Webroot.php (2)
115-118: Signature alignment and message formatting look correct.Method now matches HandlerInterface and mirrors Profile’s resolved-message style. No functional issues found.
115-121: AllresolvedMessageimplementations now use the updated(array $responses, mixed $resolved): ?stringsignature..vortex/installer/src/Prompts/Handlers/Profile.php (1)
90-99: LGTM – clear, user-friendly resolved message..vortex/installer/src/Prompts/Handlers/Starter.php (1)
94-97: Confirm necessity of pinning symfony/http-client explicitly.If drupal/cms already constrains this, forcing '^6.4' may create avoidable solver conflicts in consumer projects.
Would you like me to scan the repo for an existing direct requirement or open a follow-up to make this addition conditional on absence?
.gitignore.artifact
Outdated
| # Ignore all recipes by default. Custom recipes should be added explicitly. | ||
| recipes/* | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick (assertive)
Confirm runtime expectations for recipes in deployment artifacts; optionally guard both locations.
- Verify that provisioning/production never relies on ../recipes/* at runtime; if it does, unignore the required paths here.
- If there’s any chance recipes are mapped under web/recipes in some environments, add a defensive ignore.
# Ignore all recipes by default. Custom recipes should be added explicitly.
recipes/*
+web/recipes/*📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| # Ignore all recipes by default. Custom recipes should be added explicitly. | |
| recipes/* | |
| # Ignore all recipes by default. Custom recipes should be added explicitly. | |
| recipes/* | |
| web/recipes/* |
🤖 Prompt for AI Agents
In .gitignore.artifact around lines 36 to 38, the review asks you to confirm
whether runtime/provisioning ever depends on ../recipes/* and to defensively
cover alternate locations; verify that production/provisioning does not require
files under ../recipes at runtime and if it does, remove or adjust this ignore
to allow those specific paths, otherwise add an additional ignore entry for
web/recipes (or other mapped locations) so artifacts remain consistent across
environments; update the .gitignore.artifact accordingly and document the
decision in the PR description.
| * @param mixed $resolved | ||
| * The resolved value from resolvedValue(). | ||
| * | ||
| * @return string|null | ||
| * The message to display, or null if no message needed. | ||
| */ | ||
| public function resolvedMessage(array $responses): ?string; | ||
| public function resolvedMessage(array $responses, mixed $resolved): ?string; | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Interface signature change is a BC break; ensure all implementers and call sites are updated; fix doc typos.
- Verify every HandlerInterface implementation now accepts the new $resolved param.
- Update any calls to resolvedMessage(...) to pass the resolved value.
- Minor doc fixes: “handlerManager” → “PromptManager”, “handlering” → “prompting”.
Search for outdated signatures and call sites:
Docblock tweak (outside the changed lines):
/**
* Get a message to display when showing the resolved value.
*
* This is used by PromptManager to show an appropriate message (via
* info(), ok(), etc.) when using a resolved value instead of prompting
* for input.
*/🏁 Script executed:
#!/bin/bash
# Implementations missing $resolved in signature
rg -nP --type=php '(?s)class\s+\w+\s+implements\s+HandlerInterface.*?\bfunction\s+resolvedMessage\s*\(\s*array\s+\$responses\s*\)' -C2
# Calls passing only $responses
rg -nP --type=php '\bresolvedMessage\s*\(\s*\$[a-zA-Z_][\w]*\s*\)'
# Interface reference to help fix doc wording
rg -nP --type=php 'PromptManager|handlerManager|handlering' .vortex/installer/src/PromptsLength of output: 797
Fix doc typos in HandlerInterface
Replace “handlerManager” with “PromptManager” and “handlering” with “prompting” in the docblock above resolvedMessage (HandlerInterface.php lines 143–144).
🤖 Prompt for AI Agents
.vortex/installer/src/Prompts/Handlers/HandlerInterface.php lines 143–156: the
docblock above resolvedMessage contains typos — change “handlerManager” to
“PromptManager” and “handlering” to “prompting” in the comment text so the
parameter/class names and verbs read correctly; keep the rest of the docblock
intact and ensure spelling/casing matches existing project conventions.
| public function resolvedValue(array $responses): null|string|bool|array { | ||
| $discovered = $this->discover(); | ||
|
|
||
| // If user selected 'custom', use the ProfileCustom response instead. | ||
| if ($v === self::CUSTOM && isset($this->responses['profile_custom'])) { | ||
| $v = $this->responses['profile_custom']; | ||
| if (!is_null($discovered)) { | ||
| return $discovered; | ||
| } | ||
|
|
||
| $t = $this->tmpDir; | ||
| $w = $this->webroot; | ||
|
|
||
| File::replaceContentInFile($t . '/.env', '/DRUPAL_PROFILE=.*/', 'DRUPAL_PROFILE=' . $v); | ||
| if (($responses[Starter::id()] ?? '') === Starter::DRUPALCMS_INSTALL_PROFILE) { | ||
| return '../recipes/drupal_cms_starter'; | ||
| } | ||
|
|
||
| if (in_array($v, [self::STANDARD, self::MINIMAL, self::DEMO_UMAMI])) { | ||
| File::rmdir(sprintf('%s/%s/profiles/your_site_profile', $t, $w)); | ||
| File::rmdir(sprintf('%s/%s/profiles/custom/your_site_profile', $t, $w)); | ||
| return NULL; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick (assertive)
Avoid hardcoding the DrupalCMS recipe path; use a class constant.
Improves maintainability and reuse in tests and other handlers.
- if (($responses[Starter::id()] ?? '') === Starter::DRUPALCMS_INSTALL_PROFILE) {
- return '../recipes/drupal_cms_starter';
+ if (($responses[Starter::id()] ?? '') === Starter::DRUPALCMS_INSTALL_PROFILE) {
+ return self::DRUPALCMS_STARTER_RECIPE;
}Add this constant near other constants (outside the diff range):
const DRUPALCMS_STARTER_RECIPE = '../recipes/drupal_cms_starter';🤖 Prompt for AI Agents
.vortex/installer/src/Prompts/Handlers/Profile.php around lines 76-88: the
DrupalCMS recipe path is hardcoded in resolvedValue; add the constant
DRUPALCMS_STARTER_RECIPE = '../recipes/drupal_cms_starter' alongside the other
class constants (outside the shown diff) and replace the string literal in
resolvedValue with self::DRUPALCMS_STARTER_RECIPE to avoid hardcoding and enable
reuse in tests/other handlers.
| // Assume that profiles provided as a path are contrib profiles. | ||
| $is_contrib_profile = str_contains($v, DIRECTORY_SEPARATOR); | ||
|
|
||
| if (in_array($v, [self::STANDARD, self::MINIMAL, self::DEMO_UMAMI]) || $is_contrib_profile) { | ||
| File::rmdir(sprintf('%s/%s/profiles/your_site_profile', $t, $w)); | ||
| File::rmdir(sprintf('%s/%s/profiles/custom/your_site_profile', $t, $w)); | ||
|
|
||
| File::replaceContentAsync([ | ||
| '/profiles/your_site_profile,' => '', | ||
| '/profiles/custom/your_site_profile,' => '', | ||
| ]); | ||
| } | ||
| else { | ||
| File::replaceContentAsync('your_site_profile', $v); | ||
| File::renameInDir($t, 'your_site_profile', $v); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick (assertive)
Fix OS-specific path detection for contrib/profile paths.
str_contains($v, DIRECTORY_SEPARATOR) fails on Windows when $v uses '/' (e.g., '../recipes/...'), leading to incorrect branch and potential bad renames. Detect both separators.
- $is_contrib_profile = str_contains($v, DIRECTORY_SEPARATOR);
+ // Detect both Unix and Windows separators in provided path.
+ $is_contrib_profile = (strpbrk($v, '/\\') !== FALSE);Consider adding a small unit test covering Unix-style and Windows-style paths.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // Assume that profiles provided as a path are contrib profiles. | |
| $is_contrib_profile = str_contains($v, DIRECTORY_SEPARATOR); | |
| if (in_array($v, [self::STANDARD, self::MINIMAL, self::DEMO_UMAMI]) || $is_contrib_profile) { | |
| File::rmdir(sprintf('%s/%s/profiles/your_site_profile', $t, $w)); | |
| File::rmdir(sprintf('%s/%s/profiles/custom/your_site_profile', $t, $w)); | |
| File::replaceContentAsync([ | |
| '/profiles/your_site_profile,' => '', | |
| '/profiles/custom/your_site_profile,' => '', | |
| ]); | |
| } | |
| else { | |
| File::replaceContentAsync('your_site_profile', $v); | |
| File::renameInDir($t, 'your_site_profile', $v); | |
| // Assume that profiles provided as a path are contrib profiles. | |
| // Detect both Unix and Windows separators in provided path. | |
| $is_contrib_profile = (strpbrk($v, '/\\') !== FALSE); | |
| if (in_array($v, [self::STANDARD, self::MINIMAL, self::DEMO_UMAMI]) || $is_contrib_profile) { | |
| File::rmdir(sprintf('%s/%s/profiles/your_site_profile', $t, $w)); | |
| File::rmdir(sprintf('%s/%s/profiles/custom/your_site_profile', $t, $w)); | |
| File::replaceContentAsync([ | |
| '/profiles/your_site_profile,' => '', | |
| '/profiles/custom/your_site_profile,' => '', | |
| ]); | |
| } | |
| else { | |
| File::replaceContentAsync('your_site_profile', $v); | |
| File::renameInDir($t, 'your_site_profile', $v); |
🤖 Prompt for AI Agents
.vortex/installer/src/Prompts/Handlers/Profile.php around lines 147 to 161: the
contrib-profile detection uses str_contains($v, DIRECTORY_SEPARATOR) which fails
when paths use the other OS separator (e.g. '/' on Windows or '\' on Unix
inputs); change the check to detect either separator (e.g. test for '/' OR '\')
so both Unix-style and Windows-style paths are treated as contrib profiles, then
keep the existing branch logic; add a unit test that passes examples with
'../recipes/...' and '..\\recipes\\...' to cover both separators.
.vortex/installer/tests/Functional/Handlers/StarterInstallTest.php
Outdated
Show resolved
Hide resolved
| @test "Workflow: profile-driven, DrupalCMS" { | ||
| rm -f .data/db.sql | ||
| export VORTEX_INSTALLER_IS_DEMO_DB_DOWNLOAD_SKIP=1 | ||
| assert_file_not_exists .data/db.sql | ||
|
|
||
| export VORTEX_INSTALLER_PROMPT_STARTER="drupalcms_profile" | ||
|
|
||
| prepare_sut "Starting fresh install WORKFLOW tests in build directory ${BUILD_DIR}" | ||
| # Assert that the database was not downloaded because VORTEX_INSTALLER_IS_DEMO_DB_DOWNLOAD_SKIP was set. | ||
| assert_file_not_exists .data/db.sql | ||
|
|
||
| assert_file_contains .env "DRUPAL_PROFILE=../recipes/drupal_cms_starter" | ||
| assert_file_not_contains .env "DEMO" | ||
| assert_file_contains composer.json "drupal/cms" | ||
| assert_file_contains composer.json "wikimedia/composer-merge-plugin" | ||
| assert_file_contains composer.json "vendor/drupal/cms/composer.json" | ||
|
|
||
| echo "VORTEX_PROVISION_TYPE=profile" >>.env | ||
|
|
||
| assert_ahoy_build | ||
| assert_gitignore | ||
|
|
||
| assert_ahoy_lint | ||
|
|
||
| assert_ahoy_test "web" "1" | ||
|
|
||
| assert_ahoy_fe | ||
|
|
||
| assert_webpage_contains "/" "This is the home page of your new site." | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick (assertive)
Add assertion for symfony/http-client to fully validate Starter::process mutations.
Starter::process() also adds symfony/http-client. Assert it to tighten the e2e check.
assert_file_contains composer.json "drupal/cms"
assert_file_contains composer.json "wikimedia/composer-merge-plugin"
assert_file_contains composer.json "vendor/drupal/cms/composer.json"
+ assert_file_contains composer.json "symfony/http-client"📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| @test "Workflow: profile-driven, DrupalCMS" { | |
| rm -f .data/db.sql | |
| export VORTEX_INSTALLER_IS_DEMO_DB_DOWNLOAD_SKIP=1 | |
| assert_file_not_exists .data/db.sql | |
| export VORTEX_INSTALLER_PROMPT_STARTER="drupalcms_profile" | |
| prepare_sut "Starting fresh install WORKFLOW tests in build directory ${BUILD_DIR}" | |
| # Assert that the database was not downloaded because VORTEX_INSTALLER_IS_DEMO_DB_DOWNLOAD_SKIP was set. | |
| assert_file_not_exists .data/db.sql | |
| assert_file_contains .env "DRUPAL_PROFILE=../recipes/drupal_cms_starter" | |
| assert_file_not_contains .env "DEMO" | |
| assert_file_contains composer.json "drupal/cms" | |
| assert_file_contains composer.json "wikimedia/composer-merge-plugin" | |
| assert_file_contains composer.json "vendor/drupal/cms/composer.json" | |
| echo "VORTEX_PROVISION_TYPE=profile" >>.env | |
| assert_ahoy_build | |
| assert_gitignore | |
| assert_ahoy_lint | |
| assert_ahoy_test "web" "1" | |
| assert_ahoy_fe | |
| assert_webpage_contains "/" "This is the home page of your new site." | |
| } | |
| @test "Workflow: profile-driven, DrupalCMS" { | |
| rm -f .data/db.sql | |
| export VORTEX_INSTALLER_IS_DEMO_DB_DOWNLOAD_SKIP=1 | |
| assert_file_not_exists .data/db.sql | |
| export VORTEX_INSTALLER_PROMPT_STARTER="drupalcms_profile" | |
| prepare_sut "Starting fresh install WORKFLOW tests in build directory ${BUILD_DIR}" | |
| # Assert that the database was not downloaded because VORTEX_INSTALLER_IS_DEMO_DB_DOWNLOAD_SKIP was set. | |
| assert_file_not_exists .data/db.sql | |
| assert_file_contains .env "DRUPAL_PROFILE=../recipes/drupal_cms_starter" | |
| assert_file_not_contains .env "DEMO" | |
| assert_file_contains composer.json "drupal/cms" | |
| assert_file_contains composer.json "wikimedia/composer-merge-plugin" | |
| assert_file_contains composer.json "vendor/drupal/cms/composer.json" | |
| assert_file_contains composer.json "symfony/http-client" | |
| echo "VORTEX_PROVISION_TYPE=profile" >>.env | |
| assert_ahoy_build | |
| assert_gitignore | |
| assert_ahoy_lint | |
| assert_ahoy_test "web" "1" | |
| assert_ahoy_fe | |
| assert_webpage_contains "/" "This is the home page of your new site." | |
| } |
🤖 Prompt for AI Agents
.vortex/tests/bats/e2e/workflow.install.profile.bats around lines 32 to 61: the
test currently asserts composer.json contains drupal/cms,
wikimedia/composer-merge-plugin and vendor/drupal/cms/composer.json but misses
the symfony/http-client package added by Starter::process(); add an assertion to
check composer.json contains "symfony/http-client" (same style as the other
assert_file_contains calls) so the e2e test verifies that Starter::process
mutations include that dependency.
| status: | ||
| label: Published | ||
| datasource_id: 'entity:node' | ||
| property_path: 'body:processed' | ||
| type: 'solr_text_custom:ngram' | ||
| property_path: status | ||
| type: boolean | ||
| dependencies: | ||
| config: | ||
| - field.storage.node.body | ||
| module: | ||
| - node | ||
| title: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick (assertive)
Switch to boolean status field is sound; plan reindex + update path.
Replacing body:processed with boolean status aligns with the new Views filter and Solr boolean filtering. On existing installs, this config in config/install won’t apply automatically—ensure a config update/post-update imports this change and triggers a full reindex to avoid stale results.
Suggested steps:
- Config deploy: drush cim -y (or a module post-update to import this specific index config).
- Rebuild + reindex: drush sapi-c && drush sapi-i -y content
🤖 Prompt for AI Agents
In web/modules/custom/ys_search/config/install/search_api.index.content.yml
around lines 61 to 69, the change from body:processed to a boolean status field
will not be applied on already-installed sites from config/install alone; add a
post-update hook (or update hook) in the module to import the updated index
config and trigger a full reindex on deploy. Implement the hook to
programmatically run the config import for this specific search_api index (or
call drush cim for the module's config), then call the Search API reindex
commands (or use the Search API PHP API to clear and index content) —
alternatively document and run drush cim -y && drush sapi-c && drush sapi-i -y
as part of the release; ensure the hook logs success/failure and is idempotent
so repeated runs are safe.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## develop #1955 +/- ##
===========================================
+ Coverage 77.26% 77.67% +0.40%
===========================================
Files 89 89
Lines 5464 5496 +32
Branches 35 35
===========================================
+ Hits 4222 4269 +47
+ Misses 1242 1227 -15 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
52dccd8 to
e0c9246
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 8
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (5)
.vortex/installer/src/Prompts/Handlers/Webroot.php (3)
49-60: Avoid conflicting inference between default() and resolvedValue().Remove hosting-provider logic from default(); keep all auto-resolution in resolvedValue() to ensure a single source of truth.
Apply:
public function default(array $responses): null|string|bool|array { - // Auto-select webroot based on hosting provider. - if (isset($responses[HostingProvider::id()])) { - return match ($responses[HostingProvider::id()]) { - HostingProvider::ACQUIA => self::DOCROOT, - HostingProvider::LAGOON => self::WEB, - default => self::WEB, - }; - } - - return NULL; + return NULL; }
98-110: Centralize provider-based resolution here.Mirror the mapping that used to live in default(), and include LAGOON/others for consistency.
Apply:
public function resolvedValue(array $responses): null|string|bool|array { $discovered = $this->discover(); if (!is_null($discovered)) { return $discovered; } - if (($responses[HostingProvider::id()] ?? '') === HostingProvider::ACQUIA) { - return self::DOCROOT; - } - - return NULL; + if (isset($responses[HostingProvider::id()])) { + return match ($responses[HostingProvider::id()]) { + HostingProvider::ACQUIA => self::DOCROOT, + HostingProvider::LAGOON => self::WEB, + default => self::WEB, + }; + } + + return NULL; }
126-146: Guard the rename to avoid collisions and missing source dir.Current rename() can fail if webroot directory is missing or target exists.
Apply:
public function process(): void { $v = $this->getResponseAsString(); $t = $this->tmpDir; $webroot = self::WEB; if ($v === $webroot) { return; } + $src = $t . DIRECTORY_SEPARATOR . $webroot; + $dst = $t . DIRECTORY_SEPARATOR . $v; + if (!is_dir($src)) { + // Nothing to move; skip safely. + return; + } + if ($src === $dst || is_dir($dst)) { + // Either same path or target already exists; skip to avoid data loss. + return; + } + File::replaceContentAsync([ sprintf('%s/', $webroot) => $v . '/', sprintf('%s\/', $webroot) => $v . '\/', sprintf(': %s', $webroot) => ': ' . $v, sprintf('=%s', $webroot) => '=' . $v, sprintf('!%s', $webroot) => '!' . $v, sprintf('/\/%s\//', $webroot) => '/' . $v . '/', sprintf('/\'\/%s\'/', $webroot) => "'/" . $v . "'", ]); - rename($t . DIRECTORY_SEPARATOR . $webroot, $t . DIRECTORY_SEPARATOR . $v); + rename($src, $dst); }.vortex/installer/src/Prompts/Handlers/Starter.php (2)
32-51: Standardize product name and wording (“Drupal CMS”, “recipe”).Use the canonical “Drupal CMS” spelling and “recipe” terminology for consistency with Composer/Drupal docs and the option label below.
- $label2 = Tui::bold('DrupalCMS, installed from profile'); + $label2 = Tui::bold('Drupal CMS, installed from recipe'); @@ - Creates a new site by {$label21} - from the DrupalCMS recipe. + Creates a new site by {$label21} + from the Drupal CMS recipe.
126-138: Use strict comparisons in postInstall branches.- if ($this->response == self::DRUPAL_LOAD_DATABASE_DEMO) { + if ($this->response === self::DRUPAL_LOAD_DATABASE_DEMO) { @@ - elseif ($this->response == self::DRUPAL_INSTALL_PROFILE || $this->response == self::DRUPALCMS_INSTALL_PROFILE) { + elseif ($this->response === self::DRUPAL_INSTALL_PROFILE || $this->response === self::DRUPALCMS_INSTALL_PROFILE) {
♻️ Duplicate comments (12)
.gitignore.artifact (1)
36-38: Also ignore web/recipes in artifacts (web is un-ignored).Because !web includes everything under web/, recipe contents under web/recipes would slip into artifacts. Add a defensive ignore.
# Ignore all recipes by default. Custom recipes should be added explicitly. recipes/* +web/recipes/*composer.json (2)
152-156: Missing installer type “drupal-recipe” — recipes won’t install.oomphinc/composer-installers-extender requires the type to be declared.
"installer-types": [ "bower-asset", "npm-asset", - "drupal-library" + "drupal-library", + "drupal-recipe" ],
6-30: Wire Drupal CMS and merge-plugin per PR objective.Add drupal/cms, require and allow wikimedia/composer-merge-plugin, and include vendor/drupal/cms/composer.json under extra.merge-plugin.
Diffs within selected ranges:
"require": { "php": ">=8.3", "composer/installers": "^2.3", "cweagans/composer-patches": "^1.7", + "drupal/cms": "^1.0", "drupal/admin_toolbar": "^3.6", ... - "webflo/drupal-finder": "^1.3" + "webflo/drupal-finder": "^1.3", + "wikimedia/composer-merge-plugin": "^2.1" },"config": { "allow-plugins": { "composer/installers": true, "cweagans/composer-patches": true, "dealerdirect/phpcodesniffer-composer-installer": true, "drupal/core-composer-scaffold": true, "ergebnis/composer-normalize": true, "oomphinc/composer-installers-extender": true, "php-http/discovery": true, "phpstan/extension-installer": true, "pyrech/composer-changelogs": true, - "tbachert/spi": true + "tbachert/spi": true, + "wikimedia/composer-merge-plugin": true },Additional block to add inside "extra" (outside the selected hunk; place near other extra keys):
"merge-plugin": { "include": [ "vendor/drupal/cms/composer.json" ], "merge-dev": false, "recurse": true, "replace": false, "ignore-duplicates": true }After changes, please run:
composer validate composer update --dry-runAlso applies to: 73-85, 92-118
.vortex/installer/src/Prompts/Handlers/HandlerInterface.php (1)
141-155: Fix doc typos: PromptManager and “prompting”.Tighten the doc to match current naming.
/** * Get a message to display when showing the resolved value. * - * This is used by handlerManager to show an appropriate message (via - * info(), ok(), etc.) when using a resolved value instead of handlering + * This is used by PromptManager to show an appropriate message (via + * info(), ok(), etc.) when using a resolved value instead of prompting * for input. *.vortex/installer/tests/Functional/Handlers/StarterInstallTest.php (1)
7-14: Fix incorrect coverage target to match the subject (Starter).This mirrors an existing comment; also drop the now-unused ProvisionType import.
Apply:
-use DrevOps\VortexInstaller\Prompts\Handlers\ProvisionType; use DrevOps\VortexInstaller\Prompts\Handlers\Starter; @@ -#[CoversClass(ProvisionType::class)] +#[CoversClass(Starter::class)] class StarterInstallTest extends AbstractInstallTestCase {.vortex/tests/bats/e2e/workflow.install.profile.bats (1)
45-47: Assert symfony/http-client addition as part of Starter::process().Repeat of a prior suggestion; tighten the e2e check.
Apply:
assert_file_contains composer.json "drupal/cms" assert_file_contains composer.json "wikimedia/composer-merge-plugin" assert_file_contains composer.json "vendor/drupal/cms/composer.json" + assert_file_contains composer.json "symfony/http-client"web/modules/custom/ys_search/config/install/search_api.index.content.yml (1)
61-69: Switch to boolean Published field is correct; ensure deploy path + full reindex.This change won’t auto-apply on existing sites via config/install. Add a post-update (or documented deploy step) to import this updated index config and trigger a full reindex to avoid stale results.
Example post-update (outside this file):
// web/modules/custom/ys_search/ys_search.post_update.php <?php use Drupal\search_api\Entity\Index; /** * Switch content index to boolean "status" and reindex. */ function ys_search_post_update_0001_status_boolean_reindex(&$sandbox = NULL) : void { /** @var \Drupal\search_api\IndexInterface|null $index */ $index = Index::load('content'); if ($index) { // Clear tracker to force reindex; actual indexing runs via cron/queue. $index->rebuildTracker(); $index->save(); } // Optionally: log a reminder to run: drush sapi-c && drush sapi-i -y content \Drupal::logger('ys_search')->notice('Search index "content" updated; run reindex.'); }.vortex/installer/src/Prompts/Handlers/Profile.php (2)
76-88: Avoid hardcoding recipe path; use a class constant.Improves reuse and keeps tests/handlers in sync.
public function resolvedValue(array $responses): null|string|bool|array { $discovered = $this->discover(); if (!is_null($discovered)) { return $discovered; } if (($responses[Starter::id()] ?? '') === Starter::DRUPALCMS_INSTALL_PROFILE) { - return '../recipes/drupal_cms_starter'; + return self::DRUPALCMS_STARTER_RECIPE; } return NULL; }Add near other constants (outside this hunk):
const DRUPALCMS_STARTER_RECIPE = '../recipes/drupal_cms_starter';
147-151: Fix OS-agnostic path detection for contrib/custom profile paths.str_contains($v, DIRECTORY_SEPARATOR) misses Unix-style paths on Windows and vice versa. Detect both separators.
- $is_contrib_profile = str_contains($v, DIRECTORY_SEPARATOR); + // Treat any path that contains '/' or '\' as an external/contrib profile. + $is_contrib_profile = (strpbrk($v, '/\\') !== FALSE);.vortex/installer/src/Prompts/PromptManager.php (2)
128-141: Guard info() against null resolved messages.resolvedMessage() returns ?string. Avoid passing null.
- info($handler->resolvedMessage($r, $resolved)); + if ($m = $handler->resolvedMessage($r, $resolved)) { + info($m); + }
166-166: Apply the same guard for Webroot messaging.Keep consistency and avoid null passed to info().
- info($handler->resolvedMessage($r, $resolved)); + if ($m = $handler->resolvedMessage($r, $resolved)) { + info($m); + }.vortex/installer/src/Prompts/Handlers/Starter.php (1)
91-113: Null-dereference risk, unchecked write, and non-strict comparison.JsonManipulator::fromFile() can return NULL; file_put_contents() can fail; and loose equality can misfire with non-string responses. Harden this block.
- if ($this->response == self::DRUPALCMS_INSTALL_PROFILE) { - $cj = JsonManipulator::fromFile($this->tmpDir . '/composer.json'); + if ($this->response === self::DRUPALCMS_INSTALL_PROFILE) { + $composerPath = $this->tmpDir . '/composer.json'; + $cj = JsonManipulator::fromFile($composerPath); + if ($cj === NULL) { + throw new \RuntimeException(sprintf('composer.json not readable at %s.', $composerPath)); + } @@ - $c = $cj->getContents(); - file_put_contents($this->tmpDir . '/composer.json', $c); + $c = $cj->getContents(); + if (file_put_contents($composerPath, $c) === FALSE) { + throw new \RuntimeException(sprintf('Failed to write %s.', $composerPath)); + }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (24)
.vortex/installer/tests/Fixtures/install/_baseline/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/_baseline/composer.jsonis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/_baseline/tests/behat/features/search.featureis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/_baseline/web/modules/custom/sw_search/config/install/search_api.index.content.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/_baseline/web/modules/custom/sw_search/config/install/views.view.search.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/deploy_type_all_circleci/.gitignore.artifactis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/deploy_type_all_gha/.gitignore.artifactis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/deploy_type_artifact/.gitignore.artifactis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/hosting_acquia/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/hosting_acquia/.gitignore.artifactis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/hosting_acquia/composer.jsonis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/hosting_acquia/docroot/modules/custom/sw_search/config/install/search_api.index.content.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/hosting_acquia/docroot/modules/custom/sw_search/config/install/views.view.search.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/names/web/modules/custom/the_force_search/config/install/search_api.index.content.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/names/web/modules/custom/the_force_search/config/install/views.view.search.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/starter_demo_db/.ignorecontentis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/starter_drupal_profile/.envis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/starter_drupalcms_profile/.envis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/starter_drupalcms_profile/composer.jsonis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/tools_groups_no_be_tests/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/tools_groups_no_be_tests_circleci/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/tools_no_phpunit/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/tools_no_phpunit_circleci/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/tools_none/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**
📒 Files selected for processing (16)
.gitignore(2 hunks).gitignore.artifact(1 hunks).vortex/installer/src/Prompts/Handlers/AbstractHandler.php(1 hunks).vortex/installer/src/Prompts/Handlers/HandlerInterface.php(1 hunks).vortex/installer/src/Prompts/Handlers/Profile.php(2 hunks).vortex/installer/src/Prompts/Handlers/Starter.php(6 hunks).vortex/installer/src/Prompts/Handlers/Webroot.php(1 hunks).vortex/installer/src/Prompts/PromptManager.php(2 hunks).vortex/installer/tests/Functional/Handlers/StarterInstallTest.php(1 hunks).vortex/installer/tests/Unit/Handlers/StarterPromptManagerTest.php(1 hunks).vortex/tests/bats/_helper.bash(0 hunks).vortex/tests/bats/e2e/workflow.install.profile.bats(1 hunks)composer.json(1 hunks)tests/behat/features/search.feature(1 hunks)web/modules/custom/ys_search/config/install/search_api.index.content.yml(1 hunks)web/modules/custom/ys_search/config/install/views.view.search.yml(1 hunks)
💤 Files with no reviewable changes (1)
- .vortex/tests/bats/_helper.bash
🧰 Additional context used
📓 Path-based instructions (3)
composer.json
📄 CodeRabbit inference engine (CLAUDE.md)
When adding JavaScript or CSS libraries as Drupal libraries with Composer, define them as inline Composer packages in the 'repositories' section of composer.json
Files:
composer.json
web/modules/custom/**
📄 CodeRabbit inference engine (CLAUDE.md)
Custom modules should be placed in 'web/modules/custom/'
Files:
web/modules/custom/ys_search/config/install/search_api.index.content.ymlweb/modules/custom/ys_search/config/install/views.view.search.yml
tests/behat/**/*.feature
📄 CodeRabbit inference engine (CLAUDE.md)
tests/behat/**/*.feature: All Behat feature files must use the standard user story format: 'As a [user type]\nI want to [action]\nSo that [benefit]'
Use consistent user types in Behat feature files: 'site visitor', 'site administrator', and 'content editor'
Do not use commas or periods in user story statements within Behat feature files
Files:
tests/behat/features/search.feature
🧬 Code graph analysis (9)
.vortex/installer/src/Prompts/Handlers/AbstractHandler.php (3)
.vortex/installer/src/Prompts/Handlers/HandlerInterface.php (1)
resolvedMessage(155-155).vortex/installer/src/Prompts/Handlers/Profile.php (1)
resolvedMessage(93-99).vortex/installer/src/Prompts/Handlers/Webroot.php (1)
resolvedMessage(115-121)
.vortex/installer/src/Prompts/Handlers/Webroot.php (3)
.vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
resolvedMessage(137-139).vortex/installer/src/Prompts/Handlers/HandlerInterface.php (1)
resolvedMessage(155-155).vortex/installer/src/Prompts/Handlers/Profile.php (1)
resolvedMessage(93-99)
.vortex/installer/src/Prompts/Handlers/HandlerInterface.php (3)
.vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
resolvedMessage(137-139).vortex/installer/src/Prompts/Handlers/Profile.php (1)
resolvedMessage(93-99).vortex/installer/src/Prompts/Handlers/Webroot.php (1)
resolvedMessage(115-121)
.vortex/installer/tests/Unit/Handlers/StarterPromptManagerTest.php (3)
.vortex/installer/src/Prompts/Handlers/Starter.php (1)
Starter(10-148).vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
id(52-62).vortex/installer/src/Prompts/Handlers/HandlerInterface.php (1)
id(19-19)
.vortex/tests/bats/e2e/workflow.install.profile.bats (2)
.vortex/tests/bats/_helper.workflow.bash (6)
prepare_sut(7-39)assert_ahoy_build(73-130)assert_gitignore(132-162)assert_ahoy_lint(413-425)assert_ahoy_test(527-544)assert_ahoy_fe(753-777).vortex/tests/bats/_helper.bash (1)
assert_webpage_contains(1022-1028)
.vortex/installer/tests/Functional/Handlers/StarterInstallTest.php (5)
.vortex/installer/src/Prompts/Handlers/Starter.php (1)
Starter(10-148).vortex/installer/src/Prompts/PromptManager.php (2)
PromptManager(58-581)makeEnvName(431-433).vortex/installer/src/Utils/Env.php (2)
Env(7-245)put(24-26).vortex/installer/tests/Unit/Handlers/StarterPromptManagerTest.php (1)
CoversClass(11-42).vortex/installer/tests/Functional/Handlers/AbstractInstallTestCase.php (1)
AbstractInstallTestCase(19-101)
.vortex/installer/src/Prompts/Handlers/Starter.php (2)
.vortex/installer/src/Utils/JsonManipulator.php (2)
JsonManipulator(10-76)fromFile(19-36).vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
AbstractHandler(10-233)
.vortex/installer/src/Prompts/Handlers/Profile.php (4)
.vortex/installer/src/Prompts/Handlers/AbstractHandler.php (4)
resolvedValue(130-132)id(52-62)resolvedMessage(137-139)getResponseAsString(191-197).vortex/installer/src/Prompts/Handlers/HandlerInterface.php (3)
resolvedValue(138-138)id(19-19)resolvedMessage(155-155).vortex/installer/src/Prompts/Handlers/Starter.php (1)
Starter(10-148).vortex/installer/src/Utils/File.php (2)
File(10-102)replaceContentAsync(59-83)
.vortex/installer/src/Prompts/PromptManager.php (4)
.vortex/installer/src/Prompts/Handlers/Profile.php (3)
Profile(10-165)resolvedValue(76-88)resolvedMessage(93-99).vortex/installer/src/Prompts/Handlers/AbstractHandler.php (3)
id(52-62)resolvedValue(130-132)resolvedMessage(137-139).vortex/installer/src/Prompts/Handlers/Webroot.php (2)
resolvedValue(98-110)resolvedMessage(115-121).vortex/installer/src/Utils/Tui.php (1)
info(42-44)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
- GitHub Check: build (0)
- GitHub Check: build (1)
- GitHub Check: vortex-test-common
- GitHub Check: vortex-test-workflow (0)
- GitHub Check: vortex-test-workflow (2)
- GitHub Check: vortex-test-workflow (3)
- GitHub Check: vortex-test-deployment (1)
- GitHub Check: vortex-test-installer (8.4)
- GitHub Check: vortex-test-installer (8.2)
- GitHub Check: vortex-test-installer (8.3)
- GitHub Check: vortex-test-docs
🔇 Additional comments (14)
composer.json (1)
133-135: Decide on recipe install path: project-root vs web/.Current path installs to recipes/{$name}, while the issue description mentions web/recipes/{$name}. Confirm the intended location and align docs/tests accordingly.
Option A (keep project-root; update docs only): no code change here.
Option B (move under web/recipes):
- "recipes/{$name}": [ + "web/recipes/{$name}": [ "type:drupal-recipe" ],.gitignore (1)
44-46: LGTM: ignore recipes by default.Matches the deployment artifact policy and avoids committing vendor-provided recipes; custom recipes can be explicitly un-ignored when needed.
.vortex/installer/src/Prompts/Handlers/HandlerInterface.php (1)
149-155: Verify BC break in HandlerInterface.resolvedMessage signature
Ensure every class implementing HandlerInterface updates resolvedMessage(array $responses, mixed $resolved) and that all invocations pass both $responses and $resolved..vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
137-139: LGTM: abstract method matches interface.Signature now aligns with HandlerInterface; no further changes needed here.
.vortex/installer/src/Prompts/Handlers/Webroot.php (1)
115-117: Signature alignment and message: OK.Matches the new HandlerInterface; message mirrors Profile’s pattern.
.vortex/installer/tests/Unit/Handlers/StarterPromptManagerTest.php (1)
23-30: Adds DrupalCMS selection path: OK.Covers second DOWN navigation; keep option order stable to avoid flakiness.
tests/behat/features/search.feature (3)
25-27: Published filtering assertions: OK.Validates exclusion of draft; keep.
31-33: Focused result assertion: OK.Single-result expectation is precise.
11-18: Unable to locate theGiven page contentstep definition—please manually confirm it handlesstatusandmoderation_statecolumns..vortex/installer/src/Prompts/Handlers/Profile.php (2)
90-99: Resolved message formatting — LGTM.Clear and consistent with Webroot messaging.
145-145: Escape backslashes and dollar signs in$vbefore callingFile::replaceContentInFile.
replaceContentInFileuses a regex‐based replacement internally; unescaped backslashes (\) or dollar signs ($) in the replacement string are treated as backreferences and will corrupt values like Windows paths (C:\path\to\dir) or strings containing “$”.Suggested refactor:
// Escape “\” and “$” for safe preg_replace replacement $safe = strtr($v, ['\\' => '\\\\', '$' => '\\$']); File::replaceContentInFile( $t . '/.env', '/^DRUPAL_PROFILE=.*/m', 'DRUPAL_PROFILE=' . $safe );Verify that
replaceContentInFileindeed usespreg_replaceinternally and test this change against your.envformats..vortex/installer/src/Prompts/Handlers/Starter.php (3)
7-7: Import looks correct.JsonManipulator is the right utility to mutate composer.json here.
14-17: New DrupalCMS option constants — LGTM.Clear naming and consistent with existing constants.
94-97: Confirm necessity of symfony/http-client.Not listed in the issue’s steps. If unused by the installer flow or recipes, omit to reduce dependency surface.
| public function options(array $responses): ?array { | ||
| return [ | ||
| self::DRUPAL_INSTALL_PROFILE => 'Drupal, installed from profile', | ||
| self::DRUPALCMS_INSTALL_PROFILE => 'DrupalCMS, installed from profile', | ||
| self::DRUPAL_LOAD_DATABASE_DEMO => 'Drupal, loaded from the demo database', | ||
| ]; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick (assertive)
Align option label with copy (“Drupal CMS”, “recipe”).
- self::DRUPALCMS_INSTALL_PROFILE => 'DrupalCMS, installed from profile',
+ self::DRUPALCMS_INSTALL_PROFILE => 'Drupal CMS, installed from recipe',📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| public function options(array $responses): ?array { | |
| return [ | |
| self::DRUPAL_INSTALL_PROFILE => 'Drupal, installed from profile', | |
| self::DRUPALCMS_INSTALL_PROFILE => 'DrupalCMS, installed from profile', | |
| self::DRUPAL_LOAD_DATABASE_DEMO => 'Drupal, loaded from the demo database', | |
| ]; | |
| } | |
| public function options(array $responses): ?array { | |
| return [ | |
| self::DRUPAL_INSTALL_PROFILE => 'Drupal, installed from profile', | |
| self::DRUPALCMS_INSTALL_PROFILE => 'Drupal CMS, installed from recipe', | |
| self::DRUPAL_LOAD_DATABASE_DEMO => 'Drupal, loaded from the demo database', | |
| ]; | |
| } |
🤖 Prompt for AI Agents
.vortex/installer/src/Prompts/Handlers/Starter.php around lines 65–71: update
the option labels to match the copy by changing occurrences of "Drupal" to
"Drupal CMS" where appropriate and replace "installed from profile" with
"installed from recipe" (so the three labels become "Drupal, installed from
recipe", "Drupal CMS, installed from recipe", and "Drupal CMS, loaded from the
demo database"). Ensure exact wording and punctuation match these strings.
e0c9246 to
f38c8d4
Compare
f38c8d4 to
1251954
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 8
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
.vortex/installer/src/Prompts/Handlers/Starter.php (1)
126-139: Use strict comparisons for response checks.Avoid type juggling on enum-like constants.
Apply this diff:
- if ($this->response == self::DRUPAL_LOAD_DATABASE_DEMO) { + if ($this->response === self::DRUPAL_LOAD_DATABASE_DEMO) { @@ - elseif ($this->response == self::DRUPAL_INSTALL_PROFILE || $this->response == self::DRUPALCMS_INSTALL_PROFILE) { + elseif ($this->response === self::DRUPAL_INSTALL_PROFILE || $this->response === self::DRUPALCMS_INSTALL_PROFILE) {
♻️ Duplicate comments (14)
web/modules/custom/ys_search/config/install/search_api.index.content.yml (1)
61-68: Published boolean field added — plan update path + reindex for existing sites.Config in config/install won’t update already-installed environments. Add a post-update to apply this field to live config and trigger a full reindex to prevent mismatches with the view filter.
Example post-update (modules/custom/ys_search/ys_search.post_update.php):
<?php use Drupal\search_api\Entity\Index; /** * Add boolean status field to Search API "content" index and queue reindex. */ function ys_search_post_update_0001_add_status_field_and_reindex(&$sandbox = NULL) { $config = \Drupal::service('config.factory')->getEditable('search_api.index.content'); $field_settings = $config->get('field_settings') ?: []; if (empty($field_settings['status'])) { $field_settings['status'] = [ 'label' => 'Published', 'datasource_id' => 'entity:node', 'property_path' => 'status', 'type' => 'boolean', 'dependencies' => ['module' => ['node']], ]; $config->set('field_settings', $field_settings)->save(); } if ($index = Index::load('content')) { // Clear and schedule full reindex. $index->clear(); $index->rebuildTracker(); $index->reindex(); } return 'Search index updated with boolean status and reindex queued.'; }tests/behat/features/search.feature (1)
18-20: Replace fixed sleep with deterministic wait for index readiness.Avoid flakiness; wait until the index reports completion before navigating.
- And I run search indexing for 3 items - And I wait for 5 seconds - And I visit "/search" + And I run search indexing for 3 items + And I wait for search indexing to complete + And I visit "/search"web/modules/custom/ys_search/config/install/views.view.search.yml (2)
210-210: Teaser view mode switch — verify all bundles have teaser configured.Ensure parity with previous output; add/adjust teaser displays where missing.
165-202: Boolean status filter is correct; drop redundant expose.remember_roles.Filter isn’t exposed; remember_roles has no effect. Clean it up.
status: id: status table: search_api_index_content field: status relationship: none group_type: group admin_label: '' plugin_id: search_api_boolean operator: '=' value: '1' group: 1 exposed: false expose: operator_id: '' label: '' description: '' use_operator: false operator: '' operator_limit_selection: false operator_list: { } identifier: '' required: false remember: false multiple: false - remember_roles: - authenticated: authenticated is_grouped: false group_info: label: '' description: '' identifier: '' optional: true widget: select multiple: false remember: false default_group: All default_group_multiple: { } group_items: { }.gitignore.artifact (1)
36-38: Add defensive ignore for web/recipes in artifacts.If any env maps recipes under web/, these would currently be included because web is un-ignored. Add a guard and confirm provisioning/runtime never requires these paths in artifacts.
# Ignore all recipes by default. Custom recipes should be added explicitly. recipes/* +web/recipes/*.gitignore (1)
34-34: Tiny wording consistency: “scaffold” lowercase.Matches prior style guidance; optional.
-# Allow Drupal Scaffold files. @see https://github.com/drupal-composer/drupal-scaffold#limitation +# Allow Drupal scaffold files. @see https://github.com/drupal-composer/drupal-scaffold#limitation.vortex/installer/src/Prompts/Handlers/HandlerInterface.php (1)
141-156: Fix doc typos and verify BC updates across implementers/call sites.
- Doc: “handlerManager” → “PromptManager”; “handlering” → “prompting”.
- Signature change is a BC break; ensure all implementers accept $resolved and all callers pass it.
/** * Get a message to display when showing the resolved value. * - * This is used by handlerManager to show an appropriate message (via - * info(), ok(), etc.) when using a resolved value instead of handlering - * for input. + * This is used by PromptManager to show an appropriate message (via + * info(), ok(), etc.) when using a resolved value instead of prompting + * for input. * * @param array $responses * Current form responses for context-aware message generation. * @param mixed $resolved * The resolved value from resolvedValue().Run to verify implementers and call sites:
#!/bin/bash # Implementations missing $resolved in signature rg -nP --type=php '(?s)class\s+\w+\s+implements\s+HandlerInterface.*?\bfunction\s+resolvedMessage\s*\(\s*array\s+\$responses\s*\)' -C2 # Calls passing only $responses rg -nP --type=php '\bresolvedMessage\s*\(\s*\$[a-zA-Z_][\w]*\s*\)(?!\s*:)'.vortex/installer/tests/Functional/Handlers/StarterInstallTest.php (1)
13-14: Fix incorrect coverage annotation (duplicate of prior feedback)This test drives Starter via env; annotate coverage for Starter and drop the unused ProvisionType import.
Apply:
-use DrevOps\VortexInstaller\Prompts\Handlers\ProvisionType; +// (no import needed) -#[CoversClass(ProvisionType::class)] +#[CoversClass(Starter::class)].vortex/tests/bats/e2e/workflow.install.profile.bats (1)
45-47: Add missing assertion for symfony/http-client added by Starter::process().Covers an important mutation and tightens the e2e check.
Apply this diff:
assert_file_contains composer.json "wikimedia/composer-merge-plugin" assert_file_contains composer.json "vendor/drupal/cms/composer.json" + assert_file_contains composer.json "symfony/http-client".vortex/installer/src/Prompts/Handlers/Starter.php (1)
29-37: Align labels/copy: “Drupal CMS”, “recipe”.Match installer wording consistently across description and options.
Apply this diff:
- $label1 = Tui::bold('Drupal, installed from profile'); + $label1 = Tui::bold('Drupal, installed from recipe'); @@ - $label2 = Tui::bold('DrupalCMS, installed from profile'); + $label2 = Tui::bold('Drupal CMS, installed from recipe'); @@ - $label3 = Tui::bold('Drupal, loaded from the demo database'); + $label3 = Tui::bold('Drupal CMS, loaded from the demo database'); @@ - self::DRUPAL_INSTALL_PROFILE => 'Drupal, installed from profile', - self::DRUPALCMS_INSTALL_PROFILE => 'DrupalCMS, installed from profile', - self::DRUPAL_LOAD_DATABASE_DEMO => 'Drupal, loaded from the demo database', + self::DRUPAL_INSTALL_PROFILE => 'Drupal, installed from recipe', + self::DRUPALCMS_INSTALL_PROFILE => 'Drupal CMS, installed from recipe', + self::DRUPAL_LOAD_DATABASE_DEMO => 'Drupal CMS, loaded from the demo database',Also applies to: 65-71
.vortex/installer/src/Prompts/Handlers/Profile.php (2)
76-88: Avoid hardcoded DrupalCMS recipe path; introduce a class constant.Improves reuse and reduces drift.
Apply this diff:
- if (($responses[Starter::id()] ?? '') === Starter::DRUPALCMS_INSTALL_PROFILE) { - return '../recipes/drupal_cms_starter'; + if (($responses[Starter::id()] ?? '') === Starter::DRUPALCMS_INSTALL_PROFILE) { + return self::DRUPALCMS_STARTER_RECIPE; }Add near other constants:
// Inside class Profile, near other constants. const DRUPALCMS_STARTER_RECIPE = '../recipes/drupal_cms_starter';
131-163: Fix OS-agnostic path detection and remove magic key for custom profile.Prevents Windows false negatives and string drift.
Apply this diff:
- // If user selected 'custom', use the ProfileCustom response instead. - if ($v === self::CUSTOM && isset($this->responses['profile_custom'])) { - $v = $this->responses['profile_custom']; + // If user selected 'custom', use the ProfileCustom response instead. + if ($v === self::CUSTOM && isset($this->responses[ProfileCustom::id()])) { + $v = $this->responses[ProfileCustom::id()]; } @@ - // Assume that profiles provided as a path are contrib profiles. - $is_contrib_profile = str_contains($v, DIRECTORY_SEPARATOR); + // Assume that profiles provided as a path are contrib profiles (handle '/' and '\'). + $is_contrib_profile = (strpbrk($v, "/\\") !== FALSE);.vortex/installer/src/Prompts/PromptManager.php (2)
133-134: Guard info() call; resolvedMessage() is nullable.Avoid passing null under strict_types; cache the message and call info() only if non-null.
- info($handler->resolvedMessage($r, $resolved)); + if ($m = $handler->resolvedMessage($r, $resolved)) { + info($m); + }
166-166: Apply the same null-guard for Webroot messaging.resolvedMessage() returns ?string; protect the info() call.
- info($handler->resolvedMessage($r, $resolved)); + if ($m = $handler->resolvedMessage($r, $resolved)) { + info($m); + }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (24)
.vortex/installer/tests/Fixtures/install/_baseline/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/_baseline/composer.jsonis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/_baseline/tests/behat/features/search.featureis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/_baseline/web/modules/custom/sw_search/config/install/search_api.index.content.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/_baseline/web/modules/custom/sw_search/config/install/views.view.search.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/deploy_type_all_circleci/.gitignore.artifactis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/deploy_type_all_gha/.gitignore.artifactis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/deploy_type_artifact/.gitignore.artifactis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/hosting_acquia/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/hosting_acquia/.gitignore.artifactis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/hosting_acquia/composer.jsonis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/hosting_acquia/docroot/modules/custom/sw_search/config/install/search_api.index.content.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/hosting_acquia/docroot/modules/custom/sw_search/config/install/views.view.search.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/names/web/modules/custom/the_force_search/config/install/search_api.index.content.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/names/web/modules/custom/the_force_search/config/install/views.view.search.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/starter_demo_db/.ignorecontentis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/starter_drupal_profile/.envis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/starter_drupalcms_profile/.envis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/starter_drupalcms_profile/composer.jsonis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/tools_groups_no_be_tests/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/tools_groups_no_be_tests_circleci/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/tools_no_phpunit/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/tools_no_phpunit_circleci/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/tools_none/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**
📒 Files selected for processing (15)
.gitignore(2 hunks).gitignore.artifact(1 hunks).vortex/installer/src/Prompts/Handlers/AbstractHandler.php(1 hunks).vortex/installer/src/Prompts/Handlers/HandlerInterface.php(1 hunks).vortex/installer/src/Prompts/Handlers/Profile.php(2 hunks).vortex/installer/src/Prompts/Handlers/Starter.php(6 hunks).vortex/installer/src/Prompts/Handlers/Webroot.php(1 hunks).vortex/installer/src/Prompts/PromptManager.php(2 hunks).vortex/installer/tests/Functional/Handlers/StarterInstallTest.php(1 hunks).vortex/installer/tests/Unit/Handlers/StarterPromptManagerTest.php(2 hunks).vortex/tests/bats/e2e/workflow.install.profile.bats(1 hunks)composer.json(1 hunks)tests/behat/features/search.feature(1 hunks)web/modules/custom/ys_search/config/install/search_api.index.content.yml(1 hunks)web/modules/custom/ys_search/config/install/views.view.search.yml(1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
composer.json
📄 CodeRabbit inference engine (CLAUDE.md)
When adding JavaScript or CSS libraries as Drupal libraries with Composer, define them as inline Composer packages in the 'repositories' section of composer.json
Files:
composer.json
tests/behat/**/*.feature
📄 CodeRabbit inference engine (CLAUDE.md)
tests/behat/**/*.feature: All Behat feature files must use the standard user story format: 'As a [user type]\nI want to [action]\nSo that [benefit]'
Use consistent user types in Behat feature files: 'site visitor', 'site administrator', and 'content editor'
Do not use commas or periods in user story statements within Behat feature files
Files:
tests/behat/features/search.feature
web/modules/custom/**
📄 CodeRabbit inference engine (CLAUDE.md)
Custom modules should be placed in 'web/modules/custom/'
Files:
web/modules/custom/ys_search/config/install/views.view.search.ymlweb/modules/custom/ys_search/config/install/search_api.index.content.yml
🧬 Code graph analysis (9)
.vortex/installer/src/Prompts/Handlers/HandlerInterface.php (3)
.vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
resolvedMessage(137-139).vortex/installer/src/Prompts/Handlers/Profile.php (1)
resolvedMessage(93-99).vortex/installer/src/Prompts/Handlers/Webroot.php (1)
resolvedMessage(115-121)
.vortex/installer/src/Prompts/Handlers/AbstractHandler.php (3)
.vortex/installer/src/Prompts/Handlers/HandlerInterface.php (1)
resolvedMessage(155-155).vortex/installer/src/Prompts/Handlers/Profile.php (1)
resolvedMessage(93-99).vortex/installer/src/Prompts/Handlers/Webroot.php (1)
resolvedMessage(115-121)
.vortex/installer/tests/Functional/Handlers/StarterInstallTest.php (5)
.vortex/installer/src/Prompts/Handlers/Starter.php (1)
Starter(10-148).vortex/installer/src/Prompts/PromptManager.php (2)
PromptManager(58-581)makeEnvName(431-433).vortex/installer/src/Utils/Env.php (2)
Env(7-245)put(24-26).vortex/installer/tests/Unit/Handlers/StarterPromptManagerTest.php (1)
CoversClass(12-47).vortex/installer/tests/Functional/Handlers/AbstractInstallTestCase.php (1)
AbstractInstallTestCase(19-101)
.vortex/tests/bats/e2e/workflow.install.profile.bats (2)
.vortex/tests/bats/_helper.workflow.bash (6)
prepare_sut(7-39)assert_ahoy_build(73-130)assert_gitignore(132-162)assert_ahoy_lint(413-425)assert_ahoy_test(527-544)assert_ahoy_fe(753-777).vortex/tests/bats/_helper.bash (1)
assert_webpage_contains(1022-1028)
.vortex/installer/tests/Unit/Handlers/StarterPromptManagerTest.php (4)
.vortex/installer/src/Prompts/Handlers/Profile.php (1)
Profile(10-165).vortex/installer/src/Prompts/Handlers/Starter.php (1)
Starter(10-148).vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
id(52-62).vortex/installer/src/Prompts/Handlers/HandlerInterface.php (1)
id(19-19)
.vortex/installer/src/Prompts/Handlers/Webroot.php (3)
.vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
resolvedMessage(137-139).vortex/installer/src/Prompts/Handlers/HandlerInterface.php (1)
resolvedMessage(155-155).vortex/installer/src/Prompts/Handlers/Profile.php (1)
resolvedMessage(93-99)
.vortex/installer/src/Prompts/Handlers/Profile.php (5)
.vortex/installer/src/Prompts/Handlers/AbstractHandler.php (4)
resolvedValue(130-132)id(52-62)resolvedMessage(137-139)getResponseAsString(191-197).vortex/installer/src/Prompts/Handlers/HandlerInterface.php (3)
resolvedValue(138-138)id(19-19)resolvedMessage(155-155).vortex/installer/src/Prompts/Handlers/Webroot.php (4)
resolvedValue(98-110)discover(65-79)resolvedMessage(115-121)process(126-146).vortex/installer/src/Prompts/Handlers/Starter.php (1)
Starter(10-148).vortex/installer/src/Utils/File.php (2)
File(10-102)replaceContentAsync(59-83)
.vortex/installer/src/Prompts/PromptManager.php (5)
.vortex/installer/src/Prompts/Handlers/Profile.php (3)
Profile(10-165)resolvedValue(76-88)resolvedMessage(93-99).vortex/installer/src/Prompts/Handlers/AbstractHandler.php (3)
id(52-62)resolvedValue(130-132)resolvedMessage(137-139).vortex/installer/src/Prompts/Handlers/HandlerInterface.php (3)
id(19-19)resolvedValue(138-138)resolvedMessage(155-155).vortex/installer/src/Prompts/Handlers/Webroot.php (2)
resolvedValue(98-110)resolvedMessage(115-121).vortex/installer/src/Utils/Tui.php (1)
info(42-44)
.vortex/installer/src/Prompts/Handlers/Starter.php (2)
.vortex/installer/src/Utils/JsonManipulator.php (2)
JsonManipulator(10-76)fromFile(19-36).vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
AbstractHandler(10-233)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: vortex-test-workflow (2)
- GitHub Check: vortex-test-workflow (0)
- GitHub Check: vortex-test-workflow (1)
- GitHub Check: vortex-test-workflow (3)
🔇 Additional comments (10)
tests/behat/features/search.feature (3)
11-14: Dataset covers published vs draft — good.Includes moderation_state and status to validate the new published-only behavior.
25-27: Assertions align with published-only filter — good.Confirms both published show, draft hidden.
31-33: Targeted query validation — good.Checks single expected hit and keeps draft excluded.
.gitignore (1)
44-46: LGTM: ignore root-level recipes/Aligns with composer installer-path to recipes/{$name}.
.vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
137-139: LGTM: base signature aligned with interface.Neutral default returning NULL remains appropriate.
.vortex/installer/src/Prompts/Handlers/Webroot.php (1)
115-121: Signature update and message formatting look correctMatches the new interface (accepts mixed $resolved) and mirrors Profile’s messaging. No issues.
.vortex/installer/tests/Unit/Handlers/StarterPromptManagerTest.php (3)
7-7: Correctly importing Profile for expectationsNeeded for the expected resolved value assertion. LGTM.
24-27: Clarified test case labelRenamed label improves readability; behavior unchanged. LGTM.
28-35: Added DrupalCMS path coverageGood addition: verifies Starter::DRUPALCMS_INSTALL_PROFILE and Profile’s resolved value '../recipes/drupal_cms_starter'.
.vortex/installer/tests/Functional/Handlers/StarterInstallTest.php (1)
1-32: No stale CoversClass annotations referencing ProvisionType found
Ripgrep search across all PHP tests yielded zero matches forCoversClass(ProvisionType::class)—no further updates required.
| File::replaceContentInFile($t . '/.env', '/DRUPAL_PROFILE=.*/', 'DRUPAL_PROFILE=' . $v); | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick (assertive)
Anchor the .env replacement to the line for DRUPAL_PROFILE (defensive).
Reduces accidental matches if the token appears elsewhere.
Apply this diff (if replaceContentInFile supports PCRE flags):
- File::replaceContentInFile($t . '/.env', '/DRUPAL_PROFILE=.*/', 'DRUPAL_PROFILE=' . $v);
+ File::replaceContentInFile($t . '/.env', '/^DRUPAL_PROFILE=.*/m', 'DRUPAL_PROFILE=' . $v);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| File::replaceContentInFile($t . '/.env', '/DRUPAL_PROFILE=.*/', 'DRUPAL_PROFILE=' . $v); | |
| File::replaceContentInFile( | |
| $t . '/.env', | |
| '/^DRUPAL_PROFILE=.*/m', | |
| 'DRUPAL_PROFILE=' . $v | |
| ); |
🤖 Prompt for AI Agents
.vortex/installer/src/Prompts/Handlers/Profile.php around lines 145-146: the
current replacement uses an unanchored pattern that can match DRUPAL_PROFILE
anywhere in the file; change it to use a line-anchored PCRE (start-of-line)
pattern with multiline mode so only the DRUPAL_PROFILE line is replaced, and
pass the multiline flag if replaceContentInFile supports PCRE flags; replace the
entire line starting with DRUPAL_PROFILE= with the new value.
| if ($this->response == self::DRUPALCMS_INSTALL_PROFILE) { | ||
| $cj = JsonManipulator::fromFile($this->tmpDir . '/composer.json'); | ||
|
|
||
| $cj->addLink('require', 'drupal/cms', '^1.0', TRUE); | ||
| $cj->addLink('require', 'wikimedia/composer-merge-plugin', '^2.1', TRUE); | ||
| $cj->addLink('require', 'symfony/http-client', '^6.4', TRUE); | ||
|
|
||
| $cj->addConfigSetting('allow-plugins.drupal/core-project-message', TRUE); | ||
| $cj->addConfigSetting('allow-plugins.wikimedia/composer-merge-plugin', TRUE); | ||
|
|
||
| $cj->addProperty('extra.merge-plugin.ignore-duplicates', FALSE); | ||
| $cj->addProperty('extra.merge-plugin.merge-false', TRUE); | ||
| $cj->addProperty('extra.merge-plugin.merge-extra', FALSE); | ||
| $cj->addProperty('extra.merge-plugin.merge-extra-deep', FALSE); | ||
| $cj->addProperty('extra.merge-plugin.merge-replace', TRUE); | ||
| $cj->addProperty('extra.merge-plugin.merge-scripts', FALSE); | ||
| $cj->addProperty('extra.merge-plugin.recurse', TRUE); | ||
| $cj->addProperty('extra.merge-plugin.replace', TRUE); | ||
| $cj->addProperty('extra.merge-plugin.require', ['vendor/drupal/cms/composer.json']); | ||
|
|
||
| $c = $cj->getContents(); | ||
| file_put_contents($this->tmpDir . '/composer.json', $c); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Verify recipe install path mapping exists (type:drupal-recipe → web/recipes/{$name}).
If not set in base composer.json, Starter should ensure it; otherwise installs will land under vendor.
Run:
🏁 Script executed:
#!/bin/bash
# Expect an installer-paths mapping for type:drupal-recipe to web/recipes/{$name}
rg -nC2 -F '"installer-paths"' composer.json
rg -nC2 -F '"type:drupal-recipe"' composer.jsonLength of output: 395
Change drupal-recipe installer-path to web/recipes/{$name}
composer.json currently maps type:drupal-recipe to "recipes/{$name}" instead of "web/recipes/{$name}".
🤖 Prompt for AI Agents
.vortex/installer/src/Prompts/Handlers/Starter.php around lines 91 to 113:
update the composer extra configuration to map the drupal-recipe installer path
to "web/recipes/{$name}" instead of the current "recipes/{$name}"; modify or add
the extra.installer-paths property via JsonManipulator->addProperty so that
'extra.installer-paths' includes 'web/recipes/{$name}' for the
'type:drupal-recipe' entry (replace the existing mapping if present), then write
the updated composer.json back as done currently.
Null-check JsonManipulator::fromFile() to avoid fatal on missing composer.json.
Current code dereferences $cj without guarding a NULL return.
Apply this diff:
- if ($this->response == self::DRUPALCMS_INSTALL_PROFILE) {
- $cj = JsonManipulator::fromFile($this->tmpDir . '/composer.json');
+ if ($this->response === self::DRUPALCMS_INSTALL_PROFILE) {
+ $composerPath = $this->tmpDir . '/composer.json';
+ $cj = JsonManipulator::fromFile($composerPath);
+ if ($cj === NULL) {
+ throw new \RuntimeException(sprintf('composer.json not found or unreadable at %s', $composerPath));
+ }
@@
- $c = $cj->getContents();
- file_put_contents($this->tmpDir . '/composer.json', $c);
+ $c = $cj->getContents();
+ if (file_put_contents($composerPath, $c) === FALSE) {
+ throw new \RuntimeException(sprintf('Failed to write composer.json to %s', $composerPath));
+ }
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if ($this->response == self::DRUPALCMS_INSTALL_PROFILE) { | |
| $cj = JsonManipulator::fromFile($this->tmpDir . '/composer.json'); | |
| $cj->addLink('require', 'drupal/cms', '^1.0', TRUE); | |
| $cj->addLink('require', 'wikimedia/composer-merge-plugin', '^2.1', TRUE); | |
| $cj->addLink('require', 'symfony/http-client', '^6.4', TRUE); | |
| $cj->addConfigSetting('allow-plugins.drupal/core-project-message', TRUE); | |
| $cj->addConfigSetting('allow-plugins.wikimedia/composer-merge-plugin', TRUE); | |
| $cj->addProperty('extra.merge-plugin.ignore-duplicates', FALSE); | |
| $cj->addProperty('extra.merge-plugin.merge-false', TRUE); | |
| $cj->addProperty('extra.merge-plugin.merge-extra', FALSE); | |
| $cj->addProperty('extra.merge-plugin.merge-extra-deep', FALSE); | |
| $cj->addProperty('extra.merge-plugin.merge-replace', TRUE); | |
| $cj->addProperty('extra.merge-plugin.merge-scripts', FALSE); | |
| $cj->addProperty('extra.merge-plugin.recurse', TRUE); | |
| $cj->addProperty('extra.merge-plugin.replace', TRUE); | |
| $cj->addProperty('extra.merge-plugin.require', ['vendor/drupal/cms/composer.json']); | |
| $c = $cj->getContents(); | |
| file_put_contents($this->tmpDir . '/composer.json', $c); | |
| } | |
| if ($this->response === self::DRUPALCMS_INSTALL_PROFILE) { | |
| $composerPath = $this->tmpDir . '/composer.json'; | |
| $cj = JsonManipulator::fromFile($composerPath); | |
| if ($cj === NULL) { | |
| throw new \RuntimeException(sprintf( | |
| 'composer.json not found or unreadable at %s', | |
| $composerPath | |
| )); | |
| } | |
| $cj->addLink('require', 'drupal/cms', '^1.0', TRUE); | |
| $cj->addLink('require', 'wikimedia/composer-merge-plugin', '^2.1', TRUE); | |
| $cj->addLink('require', 'symfony/http-client', '^6.4', TRUE); | |
| $cj->addConfigSetting('allow-plugins.drupal/core-project-message', TRUE); | |
| $cj->addConfigSetting('allow-plugins.wikimedia/composer-merge-plugin', TRUE); | |
| $cj->addProperty('extra.merge-plugin.ignore-duplicates', FALSE); | |
| $cj->addProperty('extra.merge-plugin.merge-false', TRUE); | |
| $cj->addProperty('extra.merge-plugin.merge-extra', FALSE); | |
| $cj->addProperty('extra.merge-plugin.merge-extra-deep', FALSE); | |
| $cj->addProperty('extra.merge-plugin.merge-replace', TRUE); | |
| $cj->addProperty('extra.merge-plugin.merge-scripts', FALSE); | |
| $cj->addProperty('extra.merge-plugin.recurse', TRUE); | |
| $cj->addProperty('extra.merge-plugin.replace', TRUE); | |
| $cj->addProperty( | |
| 'extra.merge-plugin.require', | |
| ['vendor/drupal/cms/composer.json'] | |
| ); | |
| $c = $cj->getContents(); | |
| if (file_put_contents($composerPath, $c) === FALSE) { | |
| throw new \RuntimeException(sprintf( | |
| 'Failed to write composer.json to %s', | |
| $composerPath | |
| )); | |
| } | |
| } |
🤖 Prompt for AI Agents
.vortex/installer/src/Prompts/Handlers/Starter.php around lines 91 to 113:
JsonManipulator::fromFile($this->tmpDir . '/composer.json') can return NULL and
the code dereferences $cj immediately causing a fatal; guard the call by
checking if $cj === NULL and handle it (e.g., create a new JsonManipulator
instance or initialize a minimal composer.json file, or log an error and abort
the installer flow) before calling
addLink/addConfigSetting/addProperty/getContents; ensure subsequent
file_put_contents only runs when $cj is valid.
| 'starter, DrupalCMS profile' => [ | ||
| static::cw(fn() => Env::put(PromptManager::makeEnvName(Starter::id()), Starter::DRUPALCMS_INSTALL_PROFILE)), | ||
| ], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick (assertive)
Optionally assert DrupalCMS composer changes
Consider an “after” closure to assert composer.json contains:
- require.drupal/cms = ^1.0
- require.wikimedia/composer-merge-plugin = ^2.1
- require.symfony/http-client = ^6.4
- extra.merge-plugin.require includes vendor/drupal/cms/composer.json
This will fail fast if Starter::process regresses.
🤖 Prompt for AI Agents
.vortex/installer/tests/Functional/Handlers/StarterInstallTest.php around lines
26 to 28: the test currently sets the starter env but does not assert that
Starter::process made the expected composer.json modifications; add an "after"
closure that reads and decodes the generated composer.json and asserts the
following keys/values exist: require["drupal/cms"] === "^1.0",
require["wikimedia/composer-merge-plugin"] === "^2.1",
require["symfony/http-client"] === "^6.4", and that
extra["merge-plugin"]["require"] includes the path to
vendor/drupal/cms/composer.json (use strict assertions so the test fails fast on
regression); implement using existing test helpers for file reads and PHPUnit
assertions (assertArrayHasKey/assertEquals/assertContains) and ensure the
closure runs after Starter::process completes.
| "recipes/{$name}": [ | ||
| "type:drupal-recipe" | ||
| ], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Mapping won’t apply unless drupal-recipe is added to installer-types.
oomphinc/composer-installers-extender requires declaring custom types. Without this, drupal-recipe packages will not install to recipes/{$name}.
"installer-types": [
"bower-asset",
"npm-asset",
- "drupal-library"
+ "drupal-library",
+ "drupal-recipe"
],Also, confirm the intended target path is recipes/{$name} (root) and not web/recipes/{$name}, as tests/env vars appear to expect ../recipes/… from web/.
🏁 Script executed:
#!/bin/bash
set -e
# Locate mapping snippet in composer.json
grep -n '"recipes/{\$name}"' -C2 composer.json
# Locate installer-types block in composer.json
grep -n '"installer-types"' -C8 composer.json
# Search for recipes path references across the repo
grep -R -n 'recipes/' -C3 .Length of output: 3975
Update composer.json installer-types
- Add
"drupal-recipe"to the"installer-types"array so thattype:drupal-recipepackages install intorecipes/{$name}. - No change needed for the target path—
recipes/{$name}(root) matches the.vortextests, which reference../recipes/…fromweb/.
🤖 Prompt for AI Agents
In composer.json around lines 133 to 135, the new package type
"type:drupal-recipe" is mapped to "recipes/{$name}" but "drupal-recipe" is not
included in the "installer-types" array; update the "installer-types" array to
include "drupal-recipe" so packages with type "drupal-recipe" are installed to
recipes/{$name} (no change to the target path required).
1251954 to
47d6ecf
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
.vortex/installer/src/Prompts/Handlers/Webroot.php (2)
98-110: Avoid duplicating resolution logic between default() and resolvedValue().default() and resolvedValue() both derive values from HostingProvider/discovery. Consider delegating default() to resolvedValue() (or extracting a shared helper) to keep behavior in one place.
126-146: Broaden replacements for JSON web-root and harden rename error handling.Add a targeted replacement for composer "web-root": "web" and fail fast if the directory rename fails.
File::replaceContentAsync([ sprintf('%s/', $webroot) => $v . '/', sprintf('%s\/', $webroot) => $v . '\/', sprintf(': %s', $webroot) => ': ' . $v, sprintf('=%s', $webroot) => '=' . $v, sprintf('!%s', $webroot) => '!' . $v, sprintf('/\/%s\//', $webroot) => '/' . $v . '/', sprintf('/\'\/%s\'/', $webroot) => "'/" . $v . "'", + // composer.json (drupal-scaffold) JSON path + sprintf('/"web-root"\s*:\s*"%s"/', $webroot) => '"web-root": "' . $v . '"', ]); - rename($t . DIRECTORY_SEPARATOR . $webroot, $t . DIRECTORY_SEPARATOR . $v); + if (!@rename($t . DIRECTORY_SEPARATOR . $webroot, $t . DIRECTORY_SEPARATOR . $v)) { + throw new \RuntimeException(sprintf( + 'Failed to rename webroot from "%s" to "%s" in %s', + $webroot, + $v, + $t + )); + }.vortex/installer/src/Prompts/Handlers/Starter.php (1)
126-137: Use strict comparisons in postInstall() branches.Minor correctness/readability improvement.
- if ($this->response == self::DRUPAL_LOAD_DATABASE_DEMO) { + if ($this->response === self::DRUPAL_LOAD_DATABASE_DEMO) { @@ - elseif ($this->response == self::DRUPAL_INSTALL_PROFILE || $this->response == self::DRUPALCMS_INSTALL_PROFILE) { + elseif ($this->response === self::DRUPAL_INSTALL_PROFILE || $this->response === self::DRUPALCMS_INSTALL_PROFILE) {
♻️ Duplicate comments (18)
.gitignore.artifact (1)
36-38: Also ignore web/recipes for parity and portability.Guard both potential installer paths to keep artifacts consistent across environments.
# Ignore all recipes by default. Custom recipes should be added explicitly. recipes/* +web/recipes/*Verification script to confirm the Composer installer path for drupal-recipe:
#!/bin/bash set -euo pipefail # Show installer-paths keys that contain "recipes/{$name}" or "web/recipes/{$name}" if command -v jq >/dev/null 2>&1; then jq -r '.extra["installer-paths"]|keys[]' composer.json | rg -n '(^|/)recipes/\{\$name\}|(^|/)web/recipes/\{\$name\}' else rg -nP '"installer-paths"\s*:\s*\{' -n composer.json -A50 | rg -n 'recipes/\{\$name\}|web/recipes/\{\$name\}' fitests/behat/features/search.feature (2)
19-21: Avoid fixed sleeps; wait deterministically for indexing.Replace static delay with a polling/wait step to reduce flakiness.
- And I wait for 5 seconds - And I visit "/search" + And I wait for search indexing to complete + And I visit "/search"
15-18: Batch index enqueue to cut noise and speed up tests.Prefer a single step if supported by your step library.
- And I add the "page" content with the title "[TEST] Test page uniquestring" to the search index - And I add the "page" content with the title "[TEST] Test page otheruniquestring" to the search index - And I add the "page" content with the title "[TEST] Test page thirduniquestring" to the search index - And I run search indexing for 3 items + And I queue all created "page" content for search indexing + And I run search indexing for 3 itemsweb/modules/custom/ys_search/config/install/views.view.search.yml (1)
210-211: Switched to teaser view mode — verify per-bundle teaser displays exist.Confirm all node bundles shown in search have a configured teaser display with expected fields; otherwise results may render inconsistently.
#!/bin/bash # List teaser displays present in repo config. fd -a 'core.entity_view_display.node.*.teaser*.yml' | sortweb/modules/custom/ys_search/config/install/search_api.index.content.yml (1)
61-69: Added boolean status field to index — align with Views filter and reindex.The mapping looks right (datasource entity:node, property_path status, type boolean). Plan a config import + full reindex so the new filter works on existing installs.
Suggested deploy steps:
- drush cim -y
- drush sapi-c
- drush sapi-i -y content
composer.json (1)
152-156: Add "drupal-recipe" to installer-types (required for custom path to take effect).Without declaring the type, oomphinc/composer-installers-extender won’t route drupal-recipe packages to recipes/{$name}.
Apply:
"installer-types": [ "bower-asset", "npm-asset", - "drupal-library" + "drupal-library", + "drupal-recipe" ],Verify:
#!/bin/bash rg -n '"installer-types"\s*:\s*\[' -n composer.json -A5.vortex/tests/bats/e2e/workflow.install.profile.bats (1)
43-49: Assert all composer mutations for DrupalCMS path (deps, config, installer-paths).Add missing assertions to catch regressions in Starter::process and composer config.
assert_file_contains .env "DRUPAL_PROFILE=../recipes/drupal_cms_starter" assert_file_not_contains .env "DEMO" assert_file_contains composer.json "drupal/cms" assert_file_contains composer.json "wikimedia/composer-merge-plugin" assert_file_contains composer.json "vendor/drupal/cms/composer.json" + assert_file_contains composer.json "symfony/http-client" + # Composer config wiring + assert_file_contains composer.json "\"allow-plugins\"" + assert_file_contains composer.json "\"wikimedia/composer-merge-plugin\"" + assert_file_contains composer.json "\"merge-plugin\"" + # Recipes support under web/ + assert_file_contains composer.json "\"type:drupal-recipe\"" + assert_file_contains composer.json "\"web/recipes/".vortex/installer/tests/Functional/Handlers/StarterInstallTest.php (2)
13-14: Fix coverage annotation to reference Starter.-#[CoversClass(ProvisionType::class)] +#[CoversClass(Starter::class)]
16-29: Add “after” assertions to validate composer.json changes for DrupalCMS flow.Verify drupal/cms, merge-plugin, http-client, merge-plugin.require, and recipes installer-path mapping.
public static function dataProviderInstall(): array { return [ 'starter, demo db' => [ static::cw(fn() => Env::put(PromptManager::makeEnvName(Starter::id()), Starter::DRUPAL_LOAD_DATABASE_DEMO)), ], 'starter, Drupal profile' => [ static::cw(fn() => Env::put(PromptManager::makeEnvName(Starter::id()), Starter::DRUPAL_INSTALL_PROFILE)), ], 'starter, DrupalCMS profile' => [ - static::cw(fn() => Env::put(PromptManager::makeEnvName(Starter::id()), Starter::DRUPALCMS_INSTALL_PROFILE)), + static::cw(fn() => Env::put(PromptManager::makeEnvName(Starter::id()), Starter::DRUPALCMS_INSTALL_PROFILE)), + static::cw(function (self $test): void { + $path = static::$sut . '/composer.json'; + $json = json_decode(file_get_contents($path), TRUE, flags: JSON_THROW_ON_ERROR); + $test->assertSame('^1.0', $json['require']['drupal/cms'] ?? null); + $test->assertSame('^2.1', $json['require']['wikimedia/composer-merge-plugin'] ?? null); + $test->assertNotEmpty($json['require']['symfony/http-client'] ?? null); + $req = $json['extra']['merge-plugin']['require'] ?? []; + $test->assertContains('vendor/drupal/cms/composer.json', $req); + $paths = $json['extra']['installer-paths'] ?? []; + $test->assertArrayHasKey('web/recipes/{$name}', $paths); + $test->assertContains('type:drupal-recipe', $paths['web/recipes/{$name}'] ?? []); + }), ], ]; }.vortex/installer/src/Prompts/Handlers/Starter.php (3)
32-37: Align copy with product terms: “Drupal CMS” and “installed from recipe”.Update labels to “Drupal CMS” and call out “recipe” for the Drupal CMS path to match docs and user-facing language.
- $label2 = Tui::bold('DrupalCMS, installed from profile'); + $label2 = Tui::bold('Drupal CMS, installed from recipe'); @@ - Creates a new site by {$label21} - from the DrupalCMS recipe. + Creates a new site by {$label21} + from the Drupal CMS recipe. @@ - self::DRUPALCMS_INSTALL_PROFILE => 'DrupalCMS, installed from profile', + self::DRUPALCMS_INSTALL_PROFILE => 'Drupal CMS, installed from recipe',Also applies to: 45-51, 65-71
94-96: Optionally widen Symfony HTTP client constraint to allow 7.x when compatible.If the Drupal CMS recipe supports Symfony 7, prefer '^6.4 || ^7.0' to ease future resolves. Confirm upstream compatibility before changing.
- $cj->addLink('require', 'symfony/http-client', '^6.4', TRUE); + $cj->addLink('require', 'symfony/http-client', '^6.4 || ^7.0', TRUE);
90-113: Guard composer.json access, use strict comparisons, and ensure recipes install under web/recipes.Prevent null deref on JsonManipulator::fromFile(), fail on write error, and set installer-paths for type:drupal-recipe → web/recipes/{$name}.
- public function process(): void { - if ($this->response == self::DRUPALCMS_INSTALL_PROFILE) { - $cj = JsonManipulator::fromFile($this->tmpDir . '/composer.json'); + public function process(): void { + if ($this->response === self::DRUPALCMS_INSTALL_PROFILE) { + $composerPath = $this->tmpDir . '/composer.json'; + $cj = JsonManipulator::fromFile($composerPath); + if ($cj === NULL) { + throw new \RuntimeException(sprintf('composer.json not found or unreadable at %s', $composerPath)); + } $cj->addLink('require', 'drupal/cms', '^1.0', TRUE); $cj->addLink('require', 'wikimedia/composer-merge-plugin', '^2.1', TRUE); - $cj->addLink('require', 'symfony/http-client', '^6.4', TRUE); + $cj->addLink('require', 'symfony/http-client', '^6.4', TRUE); $cj->addConfigSetting('allow-plugins.drupal/core-project-message', TRUE); $cj->addConfigSetting('allow-plugins.wikimedia/composer-merge-plugin', TRUE); $cj->addProperty('extra.merge-plugin.ignore-duplicates', FALSE); $cj->addProperty('extra.merge-plugin.merge-false', TRUE); $cj->addProperty('extra.merge-plugin.merge-extra', FALSE); $cj->addProperty('extra.merge-plugin.merge-extra-deep', FALSE); $cj->addProperty('extra.merge-plugin.merge-replace', TRUE); $cj->addProperty('extra.merge-plugin.merge-scripts', FALSE); $cj->addProperty('extra.merge-plugin.recurse', TRUE); $cj->addProperty('extra.merge-plugin.replace', TRUE); $cj->addProperty('extra.merge-plugin.require', ['vendor/drupal/cms/composer.json']); + + // Ensure recipes install under web/recipes/{$name}. + $paths = $cj->getProperty('extra.installer-paths') ?? []; + if (!is_array($paths) || ($paths['web/recipes/{$name}'] ?? null) !== ['type:drupal-recipe']) { + $cj->addProperty('extra.installer-paths.web/recipes/{$name}', ['type:drupal-recipe']); + } - $c = $cj->getContents(); - file_put_contents($this->tmpDir . '/composer.json', $c); + $c = $cj->getContents(); + if (file_put_contents($composerPath, $c) === FALSE) { + throw new \RuntimeException(sprintf('Failed to write composer.json to %s', $composerPath)); + } }Note: if an existing mapping points to recipes/{$name}, consider removing it to avoid ambiguous paths.
.vortex/installer/src/Prompts/PromptManager.php (2)
128-141: Guard info() to avoid passing null from resolvedMessage().resolvedMessage() returns ?string; info() requires string.
Apply:
- info($handler->resolvedMessage($r, $resolved)); + if ($m = $handler->resolvedMessage($r, $resolved)) { + info($m); + }
166-166: Apply the same null-guard for Webroot messaging.Mirror the Profile guard to prevent TypeError.
- info($handler->resolvedMessage($r, $resolved)); + if ($m = $handler->resolvedMessage($r, $resolved)) { + info($m); + }.vortex/installer/src/Prompts/Handlers/Profile.php (4)
76-88: Avoid hardcoding the DrupalCMS recipe path; use a class constant.Improves maintainability and reuse.
- if (($responses[Starter::id()] ?? '') === Starter::DRUPALCMS_INSTALL_PROFILE) { - return '../recipes/drupal_cms_starter'; + if (($responses[Starter::id()] ?? '') === Starter::DRUPALCMS_INSTALL_PROFILE) { + return self::DRUPALCMS_STARTER_RECIPE; }Add (outside this hunk):
public const DRUPALCMS_STARTER_RECIPE = '../recipes/drupal_cms_starter';
138-140: Avoid magic key; use ProfileCustom::id() (or remove branch if unreachable).Prevents string drift and aligns with PromptManager merging.
- if ($v === self::CUSTOM && isset($this->responses['profile_custom'])) { - $v = $this->responses['profile_custom']; + if ($v === self::CUSTOM && isset($this->responses[ProfileCustom::id()])) { + $v = $this->responses[ProfileCustom::id()]; }
145-146: Anchor the .env replacement to the DRUPAL_PROFILE line (defensive).Reduces accidental matches elsewhere.
- File::replaceContentInFile($t . '/.env', '/DRUPAL_PROFILE=.*/', 'DRUPAL_PROFILE=' . $v); + File::replaceContentInFile($t . '/.env', '/^DRUPAL_PROFILE=.*/m', 'DRUPAL_PROFILE=' . $v);
148-149: Fix OS-agnostic path detection for contrib/custom profiles.Detect both '/' and '' to work across platforms.
- $is_contrib_profile = str_contains($v, DIRECTORY_SEPARATOR); + // Detect Unix and Windows separators. + $is_contrib_profile = (strpbrk($v, '/\\') !== FALSE);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (24)
.vortex/installer/tests/Fixtures/install/_baseline/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/_baseline/composer.jsonis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/_baseline/tests/behat/features/search.featureis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/_baseline/web/modules/custom/sw_search/config/install/search_api.index.content.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/_baseline/web/modules/custom/sw_search/config/install/views.view.search.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/deploy_type_all_circleci/.gitignore.artifactis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/deploy_type_all_gha/.gitignore.artifactis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/deploy_type_artifact/.gitignore.artifactis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/hosting_acquia/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/hosting_acquia/.gitignore.artifactis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/hosting_acquia/composer.jsonis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/hosting_acquia/docroot/modules/custom/sw_search/config/install/search_api.index.content.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/hosting_acquia/docroot/modules/custom/sw_search/config/install/views.view.search.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/names/web/modules/custom/the_force_search/config/install/search_api.index.content.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/names/web/modules/custom/the_force_search/config/install/views.view.search.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/starter_demo_db/.ignorecontentis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/starter_drupal_profile/.envis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/starter_drupalcms_profile/.envis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/starter_drupalcms_profile/composer.jsonis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/tools_groups_no_be_tests/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/tools_groups_no_be_tests_circleci/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/tools_no_phpunit/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/tools_no_phpunit_circleci/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/tools_none/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**
📒 Files selected for processing (16)
.gitignore(2 hunks).gitignore.artifact(1 hunks).vortex/installer/src/Prompts/Handlers/AbstractHandler.php(1 hunks).vortex/installer/src/Prompts/Handlers/HandlerInterface.php(1 hunks).vortex/installer/src/Prompts/Handlers/Profile.php(2 hunks).vortex/installer/src/Prompts/Handlers/Starter.php(6 hunks).vortex/installer/src/Prompts/Handlers/Webroot.php(1 hunks).vortex/installer/src/Prompts/PromptManager.php(2 hunks).vortex/installer/tests/Functional/Handlers/StarterInstallTest.php(1 hunks).vortex/installer/tests/Unit/Handlers/StarterPromptManagerTest.php(2 hunks).vortex/tests/bats/_helper.bash(1 hunks).vortex/tests/bats/e2e/workflow.install.profile.bats(1 hunks)composer.json(1 hunks)tests/behat/features/search.feature(1 hunks)web/modules/custom/ys_search/config/install/search_api.index.content.yml(1 hunks)web/modules/custom/ys_search/config/install/views.view.search.yml(1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
composer.json
📄 CodeRabbit inference engine (CLAUDE.md)
When adding JavaScript or CSS libraries as Drupal libraries with Composer, define them as inline Composer packages in the 'repositories' section of composer.json
Files:
composer.json
web/modules/custom/**
📄 CodeRabbit inference engine (CLAUDE.md)
Custom modules should be placed in 'web/modules/custom/'
Files:
web/modules/custom/ys_search/config/install/views.view.search.ymlweb/modules/custom/ys_search/config/install/search_api.index.content.yml
tests/behat/**/*.feature
📄 CodeRabbit inference engine (CLAUDE.md)
tests/behat/**/*.feature: All Behat feature files must use the standard user story format: 'As a [user type]\nI want to [action]\nSo that [benefit]'
Use consistent user types in Behat feature files: 'site visitor', 'site administrator', and 'content editor'
Do not use commas or periods in user story statements within Behat feature files
Files:
tests/behat/features/search.feature
🧠 Learnings (1)
📚 Learning: 2025-08-08T12:02:24.652Z
Learnt from: AlexSkrypnyk
PR: drevops/vortex#1896
File: .vortex/tests/bats/unit/download-db-lagoon.bats:24-25
Timestamp: 2025-08-08T12:02:24.652Z
Learning: In .vortex/tests/bats/unit Bats tests using ../_helper.bash (run_steps), prefixing a STEPS entry with "- " denotes a negative assertion (the substring must NOT appear in output). Unprefixed entries are positive assertions. Example: "- Database dump refresh requested. Will create a new dump." asserts absence; "Database dump refresh requested. Will create a new dump." asserts presence.
Applied to files:
.vortex/tests/bats/_helper.bash
🧬 Code graph analysis (9)
.vortex/installer/src/Prompts/Handlers/Profile.php (5)
.vortex/installer/src/Prompts/Handlers/AbstractHandler.php (4)
resolvedValue(130-132)id(52-62)resolvedMessage(137-139)getResponseAsString(191-197).vortex/installer/src/Prompts/Handlers/HandlerInterface.php (3)
resolvedValue(138-138)id(19-19)resolvedMessage(155-155).vortex/installer/src/Prompts/Handlers/Webroot.php (4)
resolvedValue(98-110)discover(65-79)resolvedMessage(115-121)process(126-146).vortex/installer/src/Prompts/Handlers/Starter.php (1)
Starter(10-148).vortex/installer/src/Utils/File.php (2)
File(10-102)replaceContentAsync(59-83)
.vortex/installer/src/Prompts/Handlers/AbstractHandler.php (3)
.vortex/installer/src/Prompts/Handlers/HandlerInterface.php (1)
resolvedMessage(155-155).vortex/installer/src/Prompts/Handlers/Profile.php (1)
resolvedMessage(93-99).vortex/installer/src/Prompts/Handlers/Webroot.php (1)
resolvedMessage(115-121)
.vortex/tests/bats/e2e/workflow.install.profile.bats (2)
.vortex/tests/bats/_helper.workflow.bash (6)
prepare_sut(7-39)assert_ahoy_build(73-130)assert_gitignore(132-162)assert_ahoy_lint(413-425)assert_ahoy_test(527-544)assert_ahoy_fe(753-777).vortex/tests/bats/_helper.bash (1)
assert_webpage_contains(1022-1028)
.vortex/installer/tests/Functional/Handlers/StarterInstallTest.php (6)
.vortex/installer/src/Prompts/Handlers/ProvisionType.php (1)
ProvisionType(11-103).vortex/installer/src/Prompts/Handlers/Starter.php (1)
Starter(10-148).vortex/installer/src/Prompts/PromptManager.php (2)
PromptManager(58-581)makeEnvName(431-433).vortex/installer/src/Utils/Env.php (2)
Env(7-245)put(24-26).vortex/installer/tests/Unit/Handlers/StarterPromptManagerTest.php (1)
CoversClass(12-47).vortex/installer/tests/Functional/Handlers/AbstractInstallTestCase.php (1)
AbstractInstallTestCase(19-101)
.vortex/installer/src/Prompts/Handlers/HandlerInterface.php (3)
.vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
resolvedMessage(137-139).vortex/installer/src/Prompts/Handlers/Profile.php (1)
resolvedMessage(93-99).vortex/installer/src/Prompts/Handlers/Webroot.php (1)
resolvedMessage(115-121)
.vortex/installer/tests/Unit/Handlers/StarterPromptManagerTest.php (3)
.vortex/installer/src/Prompts/Handlers/Profile.php (1)
Profile(10-165).vortex/installer/src/Prompts/Handlers/Starter.php (1)
Starter(10-148).vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
id(52-62)
.vortex/installer/src/Prompts/Handlers/Starter.php (2)
.vortex/installer/src/Utils/JsonManipulator.php (2)
JsonManipulator(10-76)fromFile(19-36).vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
AbstractHandler(10-233)
.vortex/installer/src/Prompts/Handlers/Webroot.php (3)
.vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
resolvedMessage(137-139).vortex/installer/src/Prompts/Handlers/HandlerInterface.php (1)
resolvedMessage(155-155).vortex/installer/src/Prompts/Handlers/Profile.php (1)
resolvedMessage(93-99)
.vortex/installer/src/Prompts/PromptManager.php (7)
.vortex/installer/src/Prompts/Handlers/Profile.php (3)
Profile(10-165)resolvedValue(76-88)resolvedMessage(93-99).vortex/installer/src/Prompts/Handlers/AbstractHandler.php (3)
id(52-62)resolvedValue(130-132)resolvedMessage(137-139).vortex/installer/src/Prompts/Handlers/HandlerInterface.php (3)
id(19-19)resolvedValue(138-138)resolvedMessage(155-155).vortex/installer/src/Prompts/Handlers/Webroot.php (2)
resolvedValue(98-110)resolvedMessage(115-121).vortex/installer/src/Utils/Tui.php (1)
info(42-44)scripts/custom/provision-10-example.sh (1)
info(22-22)scripts/vortex/update-vortex.sh (1)
info(46-46)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (13)
- GitHub Check: build (0)
- GitHub Check: build (1)
- GitHub Check: vortex-test-installer (8.2)
- GitHub Check: vortex-test-installer (8.4)
- GitHub Check: vortex-test-installer (8.3)
- GitHub Check: vortex-test-workflow (2)
- GitHub Check: vortex-test-workflow (3)
- GitHub Check: vortex-test-deployment (0)
- GitHub Check: vortex-test-deployment (1)
- GitHub Check: vortex-test-workflow (0)
- GitHub Check: vortex-test-common
- GitHub Check: vortex-test-workflow (1)
- GitHub Check: vortex-test-docs
🔇 Additional comments (12)
.vortex/tests/bats/_helper.bash (1)
535-535: Good fix: avoid overbroad “#;” assertion; keep explicit marker checks.The generic match was prone to false positives; retaining “#;<” and “#;>” checks preserves intent.
.vortex/installer/src/Prompts/Handlers/HandlerInterface.php (1)
141-156: Fix doc typos in HandlerInterfaceUpdate wording in the docblock to reference PromptManager and replace “handlering” with “prompting”:
- * This is used by handlerManager to show an appropriate message (via - * info(), ok(), etc.) when using a resolved value instead of handlering + * This is used by PromptManager to show an appropriate message (via + * info(), ok(), etc.) when using a resolved value instead of prompting.gitignore (2)
34-34: Wording tweak looks fine.
44-46: Drop theweb/recipes/*rule — it’s unused
Composer’s installer-paths place recipes inrecipes/{$name}, not underweb/recipes/, so ignoringweb/recipes/*is unnecessary.Likely an incorrect or invalid review comment.
web/modules/custom/ys_search/config/install/views.view.search.yml (1)
166-175: Published-only filter wiring looks correct.Boolean filter targets the index’s status field with operator "=" and value "1". Good.
composer.json (1)
133-135: Installer path for recipes is correctly defined.recipes/{$name} matches expected usage from web/ as ../recipes/… in tests.
.vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
137-139: Signature updated to include $resolved — consistent with HandlerInterface.Matches interface; no further action.
.vortex/installer/tests/Unit/Handlers/StarterPromptManagerTest.php (3)
7-7: Importing Profile for new expectation is correct.
24-27: Renamed case label — fine.
28-35: Added DrupalCMS profile test case — aligns with resolver behavior.Expects Starter::DRUPALCMS_INSTALL_PROFILE and Profile path ../recipes/drupal_cms_starter; matches Profile::resolvedValue.
.vortex/installer/src/Prompts/Handlers/Webroot.php (1)
115-117: LGTM: resolvedMessage() now relies on resolved value.Signature aligns with HandlerInterface; message formatting is consistent with Profile.
.vortex/installer/src/Prompts/Handlers/Profile.php (1)
90-99: LGTM: resolvedMessage() contract and behavior are correct.
| exposed: false | ||
| expose: | ||
| operator_id: '' | ||
| label: '' | ||
| description: '' | ||
| use_operator: false | ||
| operator: '' | ||
| operator_limit_selection: false | ||
| operator_list: { } | ||
| identifier: '' | ||
| required: false | ||
| remember: false | ||
| multiple: false | ||
| remember_roles: | ||
| authenticated: authenticated | ||
| is_grouped: false | ||
| group_info: | ||
| label: '' | ||
| description: '' | ||
| identifier: '' | ||
| optional: true | ||
| widget: select | ||
| multiple: false | ||
| remember: false | ||
| default_group: All | ||
| default_group_multiple: { } | ||
| group_items: { } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick (assertive)
Drop unused expose/group config for non-exposed boolean filter.
Since exposed: false, the expose/remember_roles and group_info blocks are redundant noise.
Apply:
group: 1
- exposed: false
- expose:
- operator_id: ''
- label: ''
- description: ''
- use_operator: false
- operator: ''
- operator_limit_selection: false
- operator_list: { }
- identifier: ''
- required: false
- remember: false
- multiple: false
- remember_roles:
- authenticated: authenticated
- is_grouped: false
- group_info:
- label: ''
- description: ''
- identifier: ''
- optional: true
- widget: select
- multiple: false
- remember: false
- default_group: All
- default_group_multiple: { }
- group_items: { }
+ exposed: false📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| exposed: false | |
| expose: | |
| operator_id: '' | |
| label: '' | |
| description: '' | |
| use_operator: false | |
| operator: '' | |
| operator_limit_selection: false | |
| operator_list: { } | |
| identifier: '' | |
| required: false | |
| remember: false | |
| multiple: false | |
| remember_roles: | |
| authenticated: authenticated | |
| is_grouped: false | |
| group_info: | |
| label: '' | |
| description: '' | |
| identifier: '' | |
| optional: true | |
| widget: select | |
| multiple: false | |
| remember: false | |
| default_group: All | |
| default_group_multiple: { } | |
| group_items: { } | |
| group: 1 | |
| exposed: false |
🤖 Prompt for AI Agents
In web/modules/custom/ys_search/config/install/views.view.search.yml around
lines 176 to 202, the view element is set to exposed: false but still contains
the redundant expose (including remember_roles) and group_info blocks; remove
the entire expose subtree (operator_id through remember_roles) and the
group_info block for this non-exposed boolean filter so the YAML only contains
the relevant properties (exposed: false and any required basic flags), ensuring
indentation and YAML structure remain valid.
47d6ecf to
97021c9
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
.vortex/installer/src/Prompts/Handlers/Starter.php (1)
126-133: Use strict comparison in postInstall.Consistency and type safety.
Apply:
- if ($this->response == self::DRUPAL_LOAD_DATABASE_DEMO) { + if ($this->response === self::DRUPAL_LOAD_DATABASE_DEMO) { @@ - elseif ($this->response == self::DRUPAL_INSTALL_PROFILE || $this->response == self::DRUPALCMS_INSTALL_PROFILE) { + elseif ($this->response === self::DRUPAL_INSTALL_PROFILE || $this->response === self::DRUPALCMS_INSTALL_PROFILE) {
♻️ Duplicate comments (16)
composer.json (1)
133-135: Add drupal-recipe to installer-types or mapping won’t apply.oomphinc/composer-installers-extender only honors custom type mappings declared in extra.installer-types. Currently, drupal-recipe is missing, so packages of type:drupal-recipe won’t be installed into recipes/{$name}.
Add the type to installer-types:
"extra": { "installer-types": [ "bower-asset", "npm-asset", "drupal-library", "drupal-recipe" ] }Verify in-repo:
#!/bin/bash rg -n '"installer-types"' -n -C4 composer.json jq -r '.extra["installer-types"][]?' composer.json 2>/dev/null | grep -q '^drupal-recipe$' && echo "OK: drupal-recipe present" || echo "MISSING: add drupal-recipe to extra.installer-types".vortex/installer/src/Prompts/Handlers/HandlerInterface.php (1)
149-156: BC break: resolvedMessage now requires $resolved—ensure all implementers and call sites are updated.Signature change to resolvedMessage(array $responses, mixed $resolved) is correct; verify all handlers implement it and all callers pass $resolved. Also fix doc typos in this block (“handlerManager” → “PromptManager”; “handlering” → “prompting”).
Run:
#!/bin/bash # Implementations missing $resolved rg -nP --type=php '(?s)class\s+\w+\s+implements\s+HandlerInterface.*?\bfunction\s+resolvedMessage\s*\(\s*array\s+\$responses\s*\)' -C2 # Calls not passing $resolved rg -nP --type=php '\bresolvedMessage\s*\(\s*\$[a-zA-Z_][\w]*\s*\)' .vortex/installer | grep -v ','Doc tweak example:
/** * Get a message to display when showing the resolved value. * * This is used by PromptManager to show an appropriate message (via * info(), ok(), etc.) when using a resolved value instead of prompting * for input. */web/modules/custom/ys_search/config/install/search_api.index.content.yml (1)
61-69: Published status field: good; plan update + reindex for existing sites.The boolean status mapping is correct and aligns with the view filter. Ensure you ship a post-update (or documented deploy step) to import this index config and trigger a full reindex to avoid stale results on already-installed sites.
web/modules/custom/ys_search/config/install/views.view.search.yml (2)
210-210: Switch to teaser view mode — verify display parity per bundle.Confirm every indexed content type has a properly configured teaser display to avoid unintended field changes.
176-202: Remove redundant expose/group blocks for a non-exposed filter.Since exposed: false, drop the expose and group_info subtrees to reduce config noise.
Apply:
group: 1 - exposed: false - expose: - operator_id: '' - label: '' - description: '' - use_operator: false - operator: '' - operator_limit_selection: false - operator_list: { } - identifier: '' - required: false - remember: false - multiple: false - remember_roles: - authenticated: authenticated - is_grouped: false - group_info: - label: '' - description: '' - identifier: '' - optional: true - widget: select - multiple: false - remember: false - default_group: All - default_group_multiple: { } - group_items: { } + exposed: false + is_grouped: falsetests/behat/features/search.feature (2)
19-20: Avoid fixed sleeps; wait deterministically for index readiness.Replace the 5s sleep with a polling/wait step to reduce flakes.
- And I wait for 5 seconds - And I visit "/search" + And I wait for search indexing to complete + And I visit "/search"
15-18: Batch index enqueue to cut noise/flakiness.Prefer a single step to queue all created items and avoid hardcoding the count in the next step.
Example:
- And I add the "page" content with the title "[TEST] Test page uniquestring" to the search index - And I add the "page" content with the title "[TEST] Test page otheruniquestring" to the search index - And I add the "page" content with the title "[TEST] Test page thirduniquestring" to the search index - And I run search indexing for 3 items + And I queue all created "page" content for search indexing + And I run search indexing for all queued items.vortex/tests/bats/e2e/workflow.install.profile.bats (2)
32-61: Add missing assertion for symfony/http-client in composer.json.This verifies Starter::process mutations end-to-end.
Apply:
assert_file_contains composer.json "wikimedia/composer-merge-plugin" assert_file_contains composer.json "vendor/drupal/cms/composer.json" + assert_file_contains composer.json "symfony/http-client"
32-61: Also assert key composer config and recipe installer-path mapping.Guard against regressions for merge-plugin wiring and recipe placement under web/recipes.
Apply:
assert_file_contains composer.json "vendor/drupal/cms/composer.json" + assert_file_contains composer.json "\"allow-plugins\"" + assert_file_contains composer.json "\"wikimedia/composer-merge-plugin\"" + assert_file_contains composer.json "\"merge-plugin\"" + assert_file_contains composer.json "\"type:drupal-recipe\"" + assert_file_contains composer.json "\"installer-paths\"" + assert_file_contains composer.json "\"web/recipes/{$name}\"".vortex/installer/tests/Functional/Handlers/StarterInstallTest.php (1)
14-15: Fix incorrect coverage annotation.This test targets Starter, not ProvisionType.
Apply:
-#[CoversClass(ProvisionType::class)] +#[CoversClass(Starter::class)].vortex/installer/src/Prompts/Handlers/Starter.php (2)
32-36: Align copy: “Drupal CMS” and “recipe” wording.Matches product naming and UX text.
Apply:
- $label2 = Tui::bold('DrupalCMS, installed from profile'); + $label2 = Tui::bold('Drupal CMS, installed from recipe'); @@ - self::DRUPALCMS_INSTALL_PROFILE => 'DrupalCMS, installed from profile', + self::DRUPALCMS_INSTALL_PROFILE => 'Drupal CMS, installed from recipe',Also applies to: 65-69
91-113: Harden composer.json mutation: strict compare, null-check, write-check.Prevents fatals if composer.json is unreadable/missing and avoids silent write failures.
Apply:
- if ($this->response == self::DRUPALCMS_INSTALL_PROFILE) { - $cj = JsonManipulator::fromFile($this->tmpDir . '/composer.json'); + if ($this->response === self::DRUPALCMS_INSTALL_PROFILE) { + $composerPath = $this->tmpDir . '/composer.json'; + $cj = JsonManipulator::fromFile($composerPath); + if ($cj === NULL) { + throw new \RuntimeException(sprintf('composer.json not found or unreadable at %s', $composerPath)); + } @@ - $c = $cj->getContents(); - file_put_contents($this->tmpDir . '/composer.json', $c); + $c = $cj->getContents(); + if (file_put_contents($composerPath, $c) === FALSE) { + throw new \RuntimeException(sprintf('Failed to write composer.json to %s', $composerPath)); + }.vortex/installer/src/Prompts/PromptManager.php (2)
161-174: Apply the same helper to Webroot (and avoid unconditional info()).Use the same resolveOrPrompt helper here for consistency and safety.
- // @todo Move into centralised resolver within this class. - function (array $r, $pr, $n): string { - $handler = $this->handlers[Webroot::id()]; - $resolved = $handler->resolvedValue($r); - if (is_string($resolved)) { - info($handler->resolvedMessage($r, $resolved)); - return $resolved; - } - else { - return text(...$this->args(Webroot::class, NULL, $r)); - } - }, + function (array $r, $pr, $n): string { + return $this->resolveOrPrompt(Webroot::id(), $r, fn() => text(...$this->args(Webroot::class, NULL, $r))); + },
128-141: DRY the resolve/log-or-prompt flow into a helper (and guard logging).This block duplicates logic used later and always calls info(...). Centralize it and only log when a non-empty message is returned.
- // @todo Move into centralised resolver within this class. - function (array $r, $pr, $n): string { - $handler = $this->handlers[Profile::id()]; - $resolved = $handler->resolvedValue($r); - if (is_string($resolved)) { - info($handler->resolvedMessage($r, $resolved)); - return $resolved; - } - else { - return (string) select(...$this->args(Profile::class)); - } - }, + function (array $r, $pr, $n): string { + return $this->resolveOrPrompt(Profile::id(), $r, fn() => select(...$this->args(Profile::class))); + },Add this helper in the class:
private function resolveOrPrompt(string $id, array $r, callable $prompt): string { $handler = $this->handlers[$id]; $resolved = $handler->resolvedValue($r); if (is_string($resolved)) { if ($m = $handler->resolvedMessage($r, $resolved)) { info($m); } return $resolved; } return (string) $prompt(); }.vortex/installer/src/Prompts/Handlers/Profile.php (2)
76-88: Avoid hardcoding DrupalCMS recipe path; use a class constant.Improves maintainability and reuse (tests, other handlers).
if (($responses[Starter::id()] ?? '') === Starter::DRUPALCMS_INSTALL_PROFILE) { - return '../recipes/drupal_cms_starter'; + return self::DRUPALCMS_STARTER_RECIPE; }Add near other constants:
const DRUPALCMS_STARTER_RECIPE = '../recipes/drupal_cms_starter';
131-163: Fix Windows path detection for contrib profiles; anchor .env replacement.
- str_contains($v, DIRECTORY_SEPARATOR) mis-detects paths on Windows when $v uses '/'; this can wrongly take the “custom rename” branch and attempt to rename to a path with separators. Detect both '/' and '' to reliably classify contrib/profile paths.
- Anchor DRUPAL_PROFILE replacement to the line to avoid accidental matches.
- File::replaceContentInFile($t . '/.env', '/DRUPAL_PROFILE=.*/', 'DRUPAL_PROFILE=' . $v); + File::replaceContentInFile($t . '/.env', '/^DRUPAL_PROFILE=.*/m', 'DRUPAL_PROFILE=' . $v); - // Assume that profiles provided as a path are contrib profiles. - $is_contrib_profile = str_contains($v, DIRECTORY_SEPARATOR); + // Treat values containing either Unix or Windows separators as contrib paths. + $is_contrib_profile = (strpbrk($v, '/\\') !== FALSE);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (23)
.vortex/installer/tests/Fixtures/install/_baseline/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/_baseline/composer.jsonis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/_baseline/phpmd.xmlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/_baseline/tests/behat/features/search.featureis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/_baseline/web/modules/custom/sw_search/config/install/search_api.index.content.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/_baseline/web/modules/custom/sw_search/config/install/views.view.search.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/hosting_acquia/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/hosting_acquia/composer.jsonis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/hosting_acquia/docroot/modules/custom/sw_search/config/install/search_api.index.content.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/hosting_acquia/docroot/modules/custom/sw_search/config/install/views.view.search.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/hosting_acquia/phpmd.xmlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/names/web/modules/custom/the_force_search/config/install/search_api.index.content.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/names/web/modules/custom/the_force_search/config/install/views.view.search.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/starter_demo_db/.ignorecontentis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/starter_drupal_profile/.envis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/starter_drupalcms_profile/.envis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/starter_drupalcms_profile/composer.jsonis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/theme_absent/phpmd.xmlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/tools_groups_no_be_tests/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/tools_groups_no_be_tests_circleci/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/tools_no_phpunit/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/tools_no_phpunit_circleci/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/tools_none/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**
📒 Files selected for processing (16)
.gitignore(2 hunks).vortex/installer/src/Prompts/Handlers/AbstractHandler.php(1 hunks).vortex/installer/src/Prompts/Handlers/HandlerInterface.php(1 hunks).vortex/installer/src/Prompts/Handlers/Profile.php(2 hunks).vortex/installer/src/Prompts/Handlers/Starter.php(6 hunks).vortex/installer/src/Prompts/Handlers/Webroot.php(1 hunks).vortex/installer/src/Prompts/PromptManager.php(2 hunks).vortex/installer/tests/Functional/Handlers/StarterInstallTest.php(1 hunks).vortex/installer/tests/Unit/Handlers/StarterPromptManagerTest.php(2 hunks).vortex/tests/bats/_helper.bash(1 hunks).vortex/tests/bats/e2e/workflow.install.profile.bats(1 hunks)composer.json(1 hunks)phpmd.xml(1 hunks)tests/behat/features/search.feature(1 hunks)web/modules/custom/ys_search/config/install/search_api.index.content.yml(1 hunks)web/modules/custom/ys_search/config/install/views.view.search.yml(1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
composer.json
📄 CodeRabbit inference engine (CLAUDE.md)
When adding JavaScript or CSS libraries as Drupal libraries with Composer, define them as inline Composer packages in the 'repositories' section of composer.json
Files:
composer.json
web/modules/custom/**
📄 CodeRabbit inference engine (CLAUDE.md)
Custom modules should be placed in 'web/modules/custom/'
Files:
web/modules/custom/ys_search/config/install/views.view.search.ymlweb/modules/custom/ys_search/config/install/search_api.index.content.yml
tests/behat/**/*.feature
📄 CodeRabbit inference engine (CLAUDE.md)
tests/behat/**/*.feature: All Behat feature files must use the standard user story format: 'As a [user type]\nI want to [action]\nSo that [benefit]'
Use consistent user types in Behat feature files: 'site visitor', 'site administrator', and 'content editor'
Do not use commas or periods in user story statements within Behat feature files
Files:
tests/behat/features/search.feature
🧠 Learnings (1)
📚 Learning: 2025-08-08T12:02:24.652Z
Learnt from: AlexSkrypnyk
PR: drevops/vortex#1896
File: .vortex/tests/bats/unit/download-db-lagoon.bats:24-25
Timestamp: 2025-08-08T12:02:24.652Z
Learning: In .vortex/tests/bats/unit Bats tests using ../_helper.bash (run_steps), prefixing a STEPS entry with "- " denotes a negative assertion (the substring must NOT appear in output). Unprefixed entries are positive assertions. Example: "- Database dump refresh requested. Will create a new dump." asserts absence; "Database dump refresh requested. Will create a new dump." asserts presence.
Applied to files:
.vortex/tests/bats/_helper.bash
🧬 Code graph analysis (9)
.vortex/installer/src/Prompts/Handlers/HandlerInterface.php (3)
.vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
resolvedMessage(137-139).vortex/installer/src/Prompts/Handlers/Profile.php (1)
resolvedMessage(93-99).vortex/installer/src/Prompts/Handlers/Webroot.php (1)
resolvedMessage(115-121)
.vortex/installer/tests/Functional/Handlers/StarterInstallTest.php (7)
.vortex/installer/src/Prompts/Handlers/ProvisionType.php (1)
ProvisionType(11-103).vortex/installer/src/Prompts/Handlers/Starter.php (1)
Starter(10-148).vortex/installer/src/Prompts/PromptManager.php (2)
PromptManager(58-581)makeEnvName(431-433).vortex/installer/src/Utils/Env.php (2)
Env(7-245)put(24-26).vortex/installer/tests/Unit/Handlers/StarterPromptManagerTest.php (1)
CoversClass(12-47).vortex/installer/tests/Functional/Handlers/AbstractInstallTestCase.php (1)
AbstractInstallTestCase(19-101).vortex/installer/tests/Functional/FunctionalTestCase.php (1)
assertSutNotContains(139-154)
.vortex/installer/tests/Unit/Handlers/StarterPromptManagerTest.php (4)
.vortex/installer/src/Prompts/Handlers/Profile.php (1)
Profile(10-165).vortex/installer/src/Prompts/Handlers/Starter.php (1)
Starter(10-148).vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
id(52-62).vortex/installer/src/Prompts/Handlers/HandlerInterface.php (1)
id(19-19)
.vortex/installer/src/Prompts/Handlers/Webroot.php (3)
.vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
resolvedMessage(137-139).vortex/installer/src/Prompts/Handlers/HandlerInterface.php (1)
resolvedMessage(155-155).vortex/installer/src/Prompts/Handlers/Profile.php (1)
resolvedMessage(93-99)
.vortex/installer/src/Prompts/Handlers/AbstractHandler.php (3)
.vortex/installer/src/Prompts/Handlers/HandlerInterface.php (1)
resolvedMessage(155-155).vortex/installer/src/Prompts/Handlers/Profile.php (1)
resolvedMessage(93-99).vortex/installer/src/Prompts/Handlers/Webroot.php (1)
resolvedMessage(115-121)
.vortex/tests/bats/e2e/workflow.install.profile.bats (2)
.vortex/tests/bats/_helper.workflow.bash (6)
prepare_sut(7-39)assert_ahoy_build(73-130)assert_gitignore(132-162)assert_ahoy_lint(413-425)assert_ahoy_test(527-544)assert_ahoy_fe(753-777).vortex/tests/bats/_helper.bash (1)
assert_webpage_contains(1022-1028)
.vortex/installer/src/Prompts/Handlers/Starter.php (3)
.vortex/installer/src/Utils/JsonManipulator.php (2)
JsonManipulator(10-76)fromFile(19-36).vortex/installer/src/Utils/Tui.php (3)
Tui(15-233)bold(74-76)underscore(78-80).vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
AbstractHandler(10-233)
.vortex/installer/src/Prompts/Handlers/Profile.php (5)
.vortex/installer/src/Prompts/Handlers/AbstractHandler.php (4)
resolvedValue(130-132)id(52-62)resolvedMessage(137-139)getResponseAsString(191-197).vortex/installer/src/Prompts/Handlers/HandlerInterface.php (3)
resolvedValue(138-138)id(19-19)resolvedMessage(155-155).vortex/installer/src/Prompts/Handlers/Starter.php (1)
Starter(10-148).vortex/installer/src/Prompts/Handlers/ProfileCustom.php (1)
ProfileCustom(9-86).vortex/installer/src/Utils/File.php (2)
File(10-102)replaceContentAsync(59-83)
.vortex/installer/src/Prompts/PromptManager.php (6)
.vortex/installer/src/Prompts/Handlers/Profile.php (3)
Profile(10-165)resolvedValue(76-88)resolvedMessage(93-99).vortex/installer/src/Prompts/Handlers/AbstractHandler.php (3)
id(52-62)resolvedValue(130-132)resolvedMessage(137-139).vortex/installer/src/Prompts/Handlers/Webroot.php (2)
resolvedValue(98-110)resolvedMessage(115-121).vortex/installer/src/Utils/Tui.php (1)
info(42-44)scripts/custom/provision-10-example.sh (1)
info(22-22)scripts/vortex/update-vortex.sh (1)
info(46-46)
🪛 GitHub Actions: Vortex - Test installer
.vortex/installer/tests/Functional/Handlers/StarterInstallTest.php
[warning] 33-33: PHPCS warning: A comma should follow the last multiline array item. Found: ) (Drupal.Arrays.Array.CommaLastItem)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
- GitHub Check: build (1)
- GitHub Check: build (0)
- GitHub Check: vortex-test-deployment (0)
- GitHub Check: vortex-test-workflow (3)
- GitHub Check: vortex-test-workflow (1)
- GitHub Check: vortex-test-workflow (0)
- GitHub Check: vortex-test-deployment (1)
- GitHub Check: vortex-test-workflow (2)
- GitHub Check: vortex-test-common
- GitHub Check: vortex-test-docs
🔇 Additional comments (12)
phpmd.xml (1)
17-17: Recipes exclude is correct.Excluding /recipes/ from PHPMD aligns with the new installer path and .gitignore. No further changes needed.
.vortex/tests/bats/_helper.bash (1)
535-535: Relaxing “#;” assertion avoids false positives; keep boundary checks.Commenting out the broad “#;” check prevents failures due to VORTEX_DEV guard markers, while still asserting “#;<” and “#;>” are stripped. Good trade-off.
.gitignore (1)
34-34: Comment tweak: LGTM.Wording change only; behavior unchanged.
web/modules/custom/ys_search/config/install/views.view.search.yml (1)
165-175: LGTM: Published-only filter.Filter configuration matches the boolean status field in the index.
tests/behat/features/search.feature (2)
11-14: Fixtures updated for moderation awareness — good.Status/moderation_state columns make expectations explicit.
25-27: Assertions match published-only behavior — good.Checks correctly include published and exclude draft.
Also applies to: 31-33
.vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
137-139: Signature aligned with interface; propagate to implementors.resolvedMessage(array $responses, mixed $resolved) matches HandlerInterface. Ensure all handlers use the new parameter and no callers rely on the old signature.
.vortex/installer/tests/Unit/Handlers/StarterPromptManagerTest.php (2)
24-27: Drupal profile path: test rename only — fine.Label change keeps expectations intact.
28-35: DrupalCMS flow covered; verify key navigation assumptions.Two DOWNs from the default selection assumes wrap-around behavior in Laravel Prompts. If that changes, the test becomes brittle; consider selecting by value or adjusting default.
.vortex/installer/src/Prompts/Handlers/Webroot.php (1)
115-117: Resolved message API change looks correct and consistent.Signature aligns with HandlerInterface; message only when $resolved is string is appropriate.
.vortex/installer/src/Prompts/Handlers/Starter.php (1)
98-109: Double-check merge-plugin keys.Confirm ‘merge-false’ and ‘require’ keys match wikimedia/composer-merge-plugin 2.x schema.
Would you like me to verify against the latest plugin docs?
.vortex/installer/src/Prompts/Handlers/Profile.php (1)
90-99: LGTM on resolvedMessage().Matches the new interface and returns a clear, user-facing line.
| # Ignore all recipes by default. Custom recipes should be added explicitly. | ||
| recipes/* | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick (assertive)
Ignoring recipes by default is sensible; consider an opt-in keep file.
If you want the directory present but empty in new repos, add an exception and commit a placeholder.
# Ignore all recipes by default. Custom recipes should be added explicitly.
recipes/*
+!recipes/.gitkeep📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| # Ignore all recipes by default. Custom recipes should be added explicitly. | |
| recipes/* | |
| # Ignore all recipes by default. Custom recipes should be added explicitly. | |
| recipes/* | |
| !recipes/.gitkeep |
🤖 Prompt for AI Agents
In .gitignore around lines 44-46, the current rule ignores the entire recipes
directory which prevents committing an empty directory; update .gitignore to
keep the directory by adding an exception for the directory (e.g., allow the
directory itself or a specific keep file) and then add and commit a placeholder
file inside recipes (commonly named .gitkeep or README) so the empty directory
is preserved in the repo.
| $cj->addLink('require', 'drupal/cms', '^1.0', TRUE); | ||
| $cj->addLink('require', 'wikimedia/composer-merge-plugin', '^2.1', TRUE); | ||
| $cj->addLink('require', 'symfony/http-client', '^6.4 || ^7.0', TRUE); | ||
|
|
||
| $cj->addConfigSetting('allow-plugins.drupal/core-project-message', TRUE); | ||
| $cj->addConfigSetting('allow-plugins.wikimedia/composer-merge-plugin', TRUE); | ||
|
|
||
| $cj->addProperty('extra.merge-plugin.ignore-duplicates', FALSE); | ||
| $cj->addProperty('extra.merge-plugin.merge-false', TRUE); | ||
| $cj->addProperty('extra.merge-plugin.merge-extra', FALSE); | ||
| $cj->addProperty('extra.merge-plugin.merge-extra-deep', FALSE); | ||
| $cj->addProperty('extra.merge-plugin.merge-replace', TRUE); | ||
| $cj->addProperty('extra.merge-plugin.merge-scripts', FALSE); | ||
| $cj->addProperty('extra.merge-plugin.recurse', TRUE); | ||
| $cj->addProperty('extra.merge-plugin.replace', TRUE); | ||
| $cj->addProperty('extra.merge-plugin.require', ['vendor/drupal/cms/composer.json']); | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Ensure recipes install under web/recipes and allow composer/installers.
Meets PR objective (type:drupal-recipe → web/recipes/{$name}) and avoids Composer 2 plugin blocks.
Apply:
$cj->addLink('require', 'drupal/cms', '^1.0', TRUE);
$cj->addLink('require', 'wikimedia/composer-merge-plugin', '^2.1', TRUE);
$cj->addLink('require', 'symfony/http-client', '^6.4 || ^7.0', TRUE);
+ $cj->addConfigSetting('allow-plugins.composer/installers', TRUE);
@@
- $cj->addProperty('extra.merge-plugin.require', ['vendor/drupal/cms/composer.json']);
+ $cj->addProperty('extra.merge-plugin.require', ['vendor/drupal/cms/composer.json']);
+ $cj->addProperty('extra.installer-paths.web/recipes/{$name}', ['type:drupal-recipe']);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| $cj->addLink('require', 'drupal/cms', '^1.0', TRUE); | |
| $cj->addLink('require', 'wikimedia/composer-merge-plugin', '^2.1', TRUE); | |
| $cj->addLink('require', 'symfony/http-client', '^6.4 || ^7.0', TRUE); | |
| $cj->addConfigSetting('allow-plugins.drupal/core-project-message', TRUE); | |
| $cj->addConfigSetting('allow-plugins.wikimedia/composer-merge-plugin', TRUE); | |
| $cj->addProperty('extra.merge-plugin.ignore-duplicates', FALSE); | |
| $cj->addProperty('extra.merge-plugin.merge-false', TRUE); | |
| $cj->addProperty('extra.merge-plugin.merge-extra', FALSE); | |
| $cj->addProperty('extra.merge-plugin.merge-extra-deep', FALSE); | |
| $cj->addProperty('extra.merge-plugin.merge-replace', TRUE); | |
| $cj->addProperty('extra.merge-plugin.merge-scripts', FALSE); | |
| $cj->addProperty('extra.merge-plugin.recurse', TRUE); | |
| $cj->addProperty('extra.merge-plugin.replace', TRUE); | |
| $cj->addProperty('extra.merge-plugin.require', ['vendor/drupal/cms/composer.json']); | |
| $cj->addLink('require', 'drupal/cms', '^1.0', TRUE); | |
| $cj->addLink('require', 'wikimedia/composer-merge-plugin', '^2.1', TRUE); | |
| $cj->addLink('require', 'symfony/http-client', '^6.4 || ^7.0', TRUE); | |
| $cj->addConfigSetting('allow-plugins.composer/installers', TRUE); | |
| $cj->addConfigSetting('allow-plugins.drupal/core-project-message', TRUE); | |
| $cj->addConfigSetting('allow-plugins.wikimedia/composer-merge-plugin', TRUE); | |
| $cj->addProperty('extra.merge-plugin.ignore-duplicates', FALSE); | |
| $cj->addProperty('extra.merge-plugin.merge-false', TRUE); | |
| $cj->addProperty('extra.merge-plugin.merge-extra', FALSE); | |
| $cj->addProperty('extra.merge-plugin.merge-extra-deep', FALSE); | |
| $cj->addProperty('extra.merge-plugin.merge-replace', TRUE); | |
| $cj->addProperty('extra.merge-plugin.merge-scripts', FALSE); | |
| $cj->addProperty('extra.merge-plugin.recurse', TRUE); | |
| $cj->addProperty('extra.merge-plugin.replace', TRUE); | |
| $cj->addProperty('extra.merge-plugin.require', ['vendor/drupal/cms/composer.json']); | |
| $cj->addProperty('extra.installer-paths.web/recipes/{$name}', ['type:drupal-recipe']); |
🤖 Prompt for AI Agents
.vortex/installer/src/Prompts/Handlers/Starter.php around lines 94-110: ensure
project composer config will install recipe packages under web/recipes and won't
be blocked by Composer 2 plugin policies; add an allow-plugins entry for
composer/installers (set to TRUE) alongside the existing allow-plugins entries,
and add an extra.installer-paths entry that maps the drupal-recipe package type
to "web/recipes/{$name}" (so recipes go into web/recipes), keeping the current
merge-plugin properties intact and avoiding any Composer 2 plugin API blocks.
.vortex/installer/tests/Functional/Handlers/StarterInstallTest.php
Outdated
Show resolved
Hide resolved
97021c9 to
ca9fb1e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
.vortex/installer/src/Prompts/Handlers/Starter.php (1)
126-138: Prefer strict comparisons in postInstall.Minor consistency/readability improvement.
- if ($this->response == self::DRUPAL_LOAD_DATABASE_DEMO) { + if ($this->response === self::DRUPAL_LOAD_DATABASE_DEMO) { @@ - elseif ($this->response == self::DRUPAL_INSTALL_PROFILE || $this->response == self::DRUPALCMS_INSTALL_PROFILE) { + elseif ($this->response === self::DRUPAL_INSTALL_PROFILE || $this->response === self::DRUPALCMS_INSTALL_PROFILE) {Also applies to: 131-131
♻️ Duplicate comments (18)
composer.json (1)
152-156: Add "drupal-recipe" to installer-types or mapping won’t apply.Without declaring the custom type, oomphinc/composer-installers-extender won’t route drupal-recipe packages to recipes/{$name}.
"installer-types": [ "bower-asset", "npm-asset", - "drupal-library" + "drupal-library", + "drupal-recipe" ],.vortex/installer/src/Prompts/Handlers/HandlerInterface.php (1)
149-156: Doc typos and BC ripple for resolvedMessage signature.Fix comment wording; ensure all implementers and call sites pass $resolved.
- * This is used by handlerManager to show an appropriate message (via - * info(), ok(), etc.) when using a resolved value instead of handlering + * This is used by PromptManager to show an appropriate message (via + * info(), ok(), etc.) when using a resolved value instead of promptingVerification (run in repo root):
rg -nP --type=php '\bfunction\s+resolvedMessage\s*\(\s*array\s+\$responses\s*\)' -C2 rg -nP --type=php '\bresolvedMessage\s*\(\s*[^,)]*\)$' -C2.gitignore (1)
44-46: Keep the recipes directory via a placeholder.This allows committing an empty recipes/ folder in new repos when desired.
# Ignore all recipes by default. Custom recipes should be added explicitly. recipes/* +!recipes/.gitkeepFollow-up: add and commit recipes/.gitkeep.
tests/behat/features/search.feature (2)
15-17: Batch the indexing step to reduce noise and flakiness.Replace the three per-item enqueue steps with a single batch step (if available).
- And I add the "page" content with the title "[TEST] Test page uniquestring" to the search index - And I add the "page" content with the title "[TEST] Test page otheruniquestring" to the search index - And I add the "page" content with the title "[TEST] Test page thirduniquestring" to the search index + And I queue all created "page" content for search indexing
19-21: Avoid fixed sleeps; wait for index readiness.Swap the hard sleep for a deterministic “wait for indexing complete” step.
- And I wait for 5 seconds + And I wait for search indexing to complete And I visit "/search"web/modules/custom/ys_search/config/install/search_api.index.content.yml (1)
61-68: Ensure deploy path reimports this config and reindexes.On existing sites, add a post-update to import this index change and trigger full reindex.
#!/bin/bash set -euo pipefail echo "🔎 Looking for ys_search post-update hooks importing index config & reindexing..." fd -a -t f 'ys_search*post_update*.php' web/modules/custom || true rg -n 'post_update|hook_post_update' web/modules/custom/ys_search || true rg -n 'sapi-?i|sapi-?c|Index::reindex|search_api' web/modules/custom/ys_search || trueweb/modules/custom/ys_search/config/install/views.view.search.yml (2)
210-210: Switch to teaser view mode — verify parity across bundles.Confirm all indexed bundles have a suitable teaser display or adjust.
#!/bin/bash set -euo pipefail echo "🔎 Listing teaser displays for node bundles..." fd -a -t f 'core.entity_view_display.node.*.teaser.yml' web || true
165-202: Trim redundant expose/group config on non-exposed filter.Since exposed: false, drop the expose and group_info blocks to reduce noise.
group: 1 exposed: false - expose: - operator_id: '' - label: '' - description: '' - use_operator: false - operator: '' - operator_limit_selection: false - operator_list: { } - identifier: '' - required: false - remember: false - multiple: false - remember_roles: - authenticated: authenticated - is_grouped: false - group_info: - label: '' - description: '' - identifier: '' - optional: true - widget: select - multiple: false - remember: false - default_group: All - default_group_multiple: { } - group_items: { } + is_grouped: false.vortex/tests/bats/e2e/workflow.install.profile.bats (2)
45-48: Also assert symfony/http-client is added by Starter::process()This was requested previously; it’s still missing here.
Apply:
assert_file_contains composer.json "wikimedia/composer-merge-plugin" assert_file_contains composer.json "vendor/drupal/cms/composer.json" + assert_file_contains composer.json "symfony/http-client"
45-50: Guard against regressions in composer config (allow-plugins, wiring, recipes)Add assertions to ensure merge-plugin wiring and recipes support are present.
Apply:
assert_file_contains composer.json "wikimedia/composer-merge-plugin" assert_file_contains composer.json "vendor/drupal/cms/composer.json" + assert_file_contains composer.json "\"allow-plugins\"" + assert_file_contains composer.json "\"wikimedia/composer-merge-plugin\"" + assert_file_contains composer.json "\"merge-plugin\"" + assert_file_contains composer.json "\"type:drupal-recipe\"".vortex/installer/tests/Functional/Handlers/StarterInstallTest.php (1)
14-15: Fix incorrect coverage target: should cover StarterThe test manipulates Starter via env; adjust CoversClass accordingly.
-#[CoversClass(ProvisionType::class)] +#[CoversClass(Starter::class)].vortex/installer/src/Prompts/Handlers/Starter.php (2)
32-36: Align labels/copy to “Drupal CMS” and “recipe”.Current labels use “DrupalCMS” and “installed from profile” while the copy says “recipe”. Align for consistency and UX polish.
- $label2 = Tui::bold('DrupalCMS, installed from profile'); + $label2 = Tui::bold('Drupal CMS, installed from recipe'); @@ - from the DrupalCMS recipe. + from the Drupal CMS recipe. @@ - self::DRUPALCMS_INSTALL_PROFILE => 'DrupalCMS, installed from profile', + self::DRUPALCMS_INSTALL_PROFILE => 'Drupal CMS, installed from recipe',Additionally (outside changed hunk), consider:
// Also change: $label1 = Tui::bold('Drupal, installed from profile'); // to: $label1 = Tui::bold('Drupal, installed from recipe'); // And: $label3 = Tui::bold('Drupal, loaded from the demo database'); // to: $label3 = Tui::bold('Drupal CMS, loaded from the demo database');Also applies to: 45-48, 67-70
91-113: Guard composer.json access, add recipe installer-path + plugin allow, and use strict comparisons.
- JsonManipulator::fromFile() can return NULL; dereferencing causes fatal.
- Missing allow-plugins for composer/installers and installer-paths mapping for type:drupal-recipe → web/recipes/{$name} (required by PR objective).
- file_put_contents() return value ignored.
- Use strict comparisons.
- if ($this->response == self::DRUPALCMS_INSTALL_PROFILE) { - $cj = JsonManipulator::fromFile($this->tmpDir . '/composer.json'); + if ($this->response === self::DRUPALCMS_INSTALL_PROFILE) { + $composerPath = $this->tmpDir . '/composer.json'; + $cj = JsonManipulator::fromFile($composerPath); + if ($cj === NULL) { + throw new \RuntimeException(sprintf('composer.json not found or unreadable at %s', $composerPath)); + } @@ $cj->addLink('require', 'drupal/cms', '^1.0', TRUE); $cj->addLink('require', 'wikimedia/composer-merge-plugin', '^2.1', TRUE); $cj->addLink('require', 'symfony/http-client', '^6.4 || ^7.0', TRUE); + // Composer 2 plugin policy and installers for recipes. + $cj->addConfigSetting('allow-plugins.composer/installers', TRUE); $cj->addConfigSetting('allow-plugins.drupal/core-project-message', TRUE); $cj->addConfigSetting('allow-plugins.wikimedia/composer-merge-plugin', TRUE); @@ $cj->addProperty('extra.merge-plugin.require', ['vendor/drupal/cms/composer.json']); + // Ensure recipes install under web/recipes/{name}. + $cj->addProperty('extra.installer-paths.web/recipes/{$name}', ['type:drupal-recipe']); - $c = $cj->getContents(); - file_put_contents($this->tmpDir . '/composer.json', $c); + $c = $cj->getContents(); + if (file_put_contents($composerPath, $c) === FALSE) { + throw new \RuntimeException(sprintf('Failed to write composer.json to %s', $composerPath)); + } }To verify, run:
#!/bin/bash # Verify composer.json mutations for Drupal CMS flow set -euo pipefail rg -n '"drupal/cms"\s*:\s*"\^1\.0"' composer.json rg -n '"wikimedia/composer-merge-plugin"\s*:\s*"\^2\.1"' composer.json rg -n '"symfony/http-client"\s*:\s*"\^6\.4 \|\| \^7\.0"' composer.json rg -n '"allow-plugins"\s*:\s*{' -n composer.json rg -n '"composer/installers"\s*:\s*true' composer.json rg -n '"wikimedia/composer-merge-plugin"\s*:\s*true' composer.json rg -n '"drupal/core-project-message"\s*:\s*true' composer.json rg -nP '"extra"\s*:\s*\{(?s).*"installer-paths"\s*:\s*\{(?s).*"web/recipes/\{\$name\}"\s*:\s*\[\s*"type:drupal-recipe"\s*\]' composer.json rg -nP '"extra"\s*:\s*\{(?s).*"merge-plugin"\s*:\s*\{(?s).*"require"\s*:\s*\[\s*"vendor/drupal/cms/composer\.json"\s*\]' composer.json.vortex/installer/src/Prompts/PromptManager.php (2)
161-174: Apply same guard for Webroot and consider DRY-ing via helper.Mirror the guard here; consider extracting a resolveOrPrompt() helper to remove duplication.
- if (is_string($resolved)) { - info($handler->resolvedMessage($r, $resolved)); + if (is_string($resolved)) { + if ($m = $handler->resolvedMessage($r, $resolved)) { + info($m); + } return $resolved; }Optional helper (add to class):
private function resolveOrPrompt(string $id, array $r, callable $prompt): string { $h = $this->handlers[$id]; $rv = $h->resolvedValue($r); if (is_string($rv)) { if ($m = $h->resolvedMessage($r, $rv)) { info($m); } return $rv; } return (string) $prompt(); }
128-141: Guard info() call when resolvedMessage is null.Avoid passing NULL to info(); keep behavior consistent with other guards.
- if (is_string($resolved)) { - info($handler->resolvedMessage($r, $resolved)); + if (is_string($resolved)) { + if ($m = $handler->resolvedMessage($r, $resolved)) { + info($m); + } return $resolved; }.vortex/installer/src/Prompts/Handlers/Profile.php (3)
76-88: Avoid hardcoded recipe path; introduce a class constant.Improves reuse and prevents string drift across handlers/tests.
- if (($responses[Starter::id()] ?? '') === Starter::DRUPALCMS_INSTALL_PROFILE) { - return '../recipes/drupal_cms_starter'; + if (($responses[Starter::id()] ?? '') === Starter::DRUPALCMS_INSTALL_PROFILE) { + return self::DRUPALCMS_STARTER_RECIPE; }Add near other constants (outside this hunk):
const DRUPALCMS_STARTER_RECIPE = '../recipes/drupal_cms_starter';
145-145: Anchor DRUPAL_PROFILE replacement to line start (defensive).Prevents accidental replacements elsewhere in the file.
- File::replaceContentInFile($t . '/.env', '/DRUPAL_PROFILE=.*/', 'DRUPAL_PROFILE=' . $v); + File::replaceContentInFile($t . '/.env', '/^DRUPAL_PROFILE=.*/m', 'DRUPAL_PROFILE=' . $v);
147-149: Cross-platform path detection for contrib/profile paths.str_contains($v, DIRECTORY_SEPARATOR) fails when separators don’t match OS; detect both.
- $is_contrib_profile = str_contains($v, DIRECTORY_SEPARATOR); + // Detect both Unix and Windows separators. + $is_contrib_profile = (strpbrk($v, '/\\') !== FALSE);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (23)
.vortex/installer/tests/Fixtures/install/_baseline/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/_baseline/composer.jsonis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/_baseline/phpmd.xmlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/_baseline/tests/behat/features/search.featureis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/_baseline/web/modules/custom/sw_search/config/install/search_api.index.content.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/_baseline/web/modules/custom/sw_search/config/install/views.view.search.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/hosting_acquia/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/hosting_acquia/composer.jsonis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/hosting_acquia/docroot/modules/custom/sw_search/config/install/search_api.index.content.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/hosting_acquia/docroot/modules/custom/sw_search/config/install/views.view.search.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/hosting_acquia/phpmd.xmlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/names/web/modules/custom/the_force_search/config/install/search_api.index.content.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/names/web/modules/custom/the_force_search/config/install/views.view.search.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/starter_demo_db/.ignorecontentis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/starter_drupal_profile/.envis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/starter_drupalcms_profile/.envis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/starter_drupalcms_profile/composer.jsonis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/theme_absent/phpmd.xmlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/tools_groups_no_be_tests/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/tools_groups_no_be_tests_circleci/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/tools_no_phpunit/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/tools_no_phpunit_circleci/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/tools_none/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**
📒 Files selected for processing (16)
.gitignore(2 hunks).vortex/installer/src/Prompts/Handlers/AbstractHandler.php(1 hunks).vortex/installer/src/Prompts/Handlers/HandlerInterface.php(1 hunks).vortex/installer/src/Prompts/Handlers/Profile.php(2 hunks).vortex/installer/src/Prompts/Handlers/Starter.php(6 hunks).vortex/installer/src/Prompts/Handlers/Webroot.php(1 hunks).vortex/installer/src/Prompts/PromptManager.php(2 hunks).vortex/installer/tests/Functional/Handlers/StarterInstallTest.php(1 hunks).vortex/installer/tests/Unit/Handlers/StarterPromptManagerTest.php(2 hunks).vortex/tests/bats/_helper.bash(1 hunks).vortex/tests/bats/e2e/workflow.install.profile.bats(1 hunks)composer.json(1 hunks)phpmd.xml(1 hunks)tests/behat/features/search.feature(1 hunks)web/modules/custom/ys_search/config/install/search_api.index.content.yml(1 hunks)web/modules/custom/ys_search/config/install/views.view.search.yml(1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
composer.json
📄 CodeRabbit inference engine (CLAUDE.md)
When adding JavaScript or CSS libraries as Drupal libraries with Composer, define them as inline Composer packages in the 'repositories' section of composer.json
Files:
composer.json
tests/behat/**/*.feature
📄 CodeRabbit inference engine (CLAUDE.md)
tests/behat/**/*.feature: All Behat feature files must use the standard user story format: 'As a [user type]\nI want to [action]\nSo that [benefit]'
Use consistent user types in Behat feature files: 'site visitor', 'site administrator', and 'content editor'
Do not use commas or periods in user story statements within Behat feature files
Files:
tests/behat/features/search.feature
web/modules/custom/**
📄 CodeRabbit inference engine (CLAUDE.md)
Custom modules should be placed in 'web/modules/custom/'
Files:
web/modules/custom/ys_search/config/install/search_api.index.content.ymlweb/modules/custom/ys_search/config/install/views.view.search.yml
🧠 Learnings (1)
📚 Learning: 2025-08-08T12:02:24.652Z
Learnt from: AlexSkrypnyk
PR: drevops/vortex#1896
File: .vortex/tests/bats/unit/download-db-lagoon.bats:24-25
Timestamp: 2025-08-08T12:02:24.652Z
Learning: In .vortex/tests/bats/unit Bats tests using ../_helper.bash (run_steps), prefixing a STEPS entry with "- " denotes a negative assertion (the substring must NOT appear in output). Unprefixed entries are positive assertions. Example: "- Database dump refresh requested. Will create a new dump." asserts absence; "Database dump refresh requested. Will create a new dump." asserts presence.
Applied to files:
.vortex/tests/bats/_helper.bash
🧬 Code graph analysis (9)
.vortex/installer/src/Prompts/Handlers/AbstractHandler.php (3)
.vortex/installer/src/Prompts/Handlers/HandlerInterface.php (1)
resolvedMessage(155-155).vortex/installer/src/Prompts/Handlers/Profile.php (1)
resolvedMessage(93-99).vortex/installer/src/Prompts/Handlers/Webroot.php (1)
resolvedMessage(115-121)
.vortex/installer/src/Prompts/Handlers/Webroot.php (3)
.vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
resolvedMessage(137-139).vortex/installer/src/Prompts/Handlers/HandlerInterface.php (1)
resolvedMessage(155-155).vortex/installer/src/Prompts/Handlers/Profile.php (1)
resolvedMessage(93-99)
.vortex/tests/bats/e2e/workflow.install.profile.bats (2)
.vortex/tests/bats/_helper.workflow.bash (6)
prepare_sut(7-39)assert_ahoy_build(73-130)assert_gitignore(132-162)assert_ahoy_lint(413-425)assert_ahoy_test(527-544)assert_ahoy_fe(753-777).vortex/tests/bats/_helper.bash (1)
assert_webpage_contains(1022-1028)
.vortex/installer/src/Prompts/Handlers/HandlerInterface.php (3)
.vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
resolvedMessage(137-139).vortex/installer/src/Prompts/Handlers/Profile.php (1)
resolvedMessage(93-99).vortex/installer/src/Prompts/Handlers/Webroot.php (1)
resolvedMessage(115-121)
.vortex/installer/tests/Unit/Handlers/StarterPromptManagerTest.php (4)
.vortex/installer/src/Prompts/Handlers/Profile.php (1)
Profile(10-165).vortex/installer/src/Prompts/Handlers/Starter.php (1)
Starter(10-148).vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
id(52-62).vortex/installer/src/Prompts/Handlers/HandlerInterface.php (1)
id(19-19)
.vortex/installer/src/Prompts/Handlers/Profile.php (5)
.vortex/installer/src/Prompts/Handlers/AbstractHandler.php (3)
resolvedValue(130-132)id(52-62)resolvedMessage(137-139).vortex/installer/src/Prompts/Handlers/HandlerInterface.php (3)
resolvedValue(138-138)id(19-19)resolvedMessage(155-155).vortex/installer/src/Prompts/Handlers/Starter.php (1)
Starter(10-148).vortex/installer/src/Prompts/Handlers/ProfileCustom.php (1)
ProfileCustom(9-86).vortex/installer/src/Utils/File.php (2)
File(10-102)replaceContentAsync(59-83)
.vortex/installer/src/Prompts/Handlers/Starter.php (2)
.vortex/installer/src/Utils/JsonManipulator.php (2)
JsonManipulator(10-76)fromFile(19-36).vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
AbstractHandler(10-233)
.vortex/installer/src/Prompts/PromptManager.php (5)
.vortex/installer/src/Prompts/Handlers/Profile.php (3)
Profile(10-165)resolvedValue(76-88)resolvedMessage(93-99).vortex/installer/src/Prompts/Handlers/AbstractHandler.php (3)
id(52-62)resolvedValue(130-132)resolvedMessage(137-139).vortex/installer/src/Prompts/Handlers/HandlerInterface.php (3)
id(19-19)resolvedValue(138-138)resolvedMessage(155-155).vortex/installer/src/Prompts/Handlers/Webroot.php (2)
resolvedValue(98-110)resolvedMessage(115-121).vortex/installer/src/Utils/Tui.php (1)
info(42-44)
.vortex/installer/tests/Functional/Handlers/StarterInstallTest.php (6)
.vortex/installer/src/Prompts/Handlers/ProvisionType.php (1)
ProvisionType(11-103).vortex/installer/src/Prompts/Handlers/Starter.php (1)
Starter(10-148).vortex/installer/src/Prompts/PromptManager.php (2)
PromptManager(58-581)makeEnvName(431-433).vortex/installer/src/Utils/Env.php (2)
Env(7-245)put(24-26).vortex/installer/tests/Functional/Handlers/AbstractInstallTestCase.php (1)
AbstractInstallTestCase(19-101).vortex/installer/tests/Functional/FunctionalTestCase.php (1)
assertSutNotContains(139-154)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (13)
- GitHub Check: build (1)
- GitHub Check: build (0)
- GitHub Check: vortex-test-deployment (0)
- GitHub Check: vortex-test-deployment (1)
- GitHub Check: vortex-test-workflow (2)
- GitHub Check: vortex-test-workflow (3)
- GitHub Check: vortex-test-workflow (1)
- GitHub Check: vortex-test-workflow (0)
- GitHub Check: vortex-test-common
- GitHub Check: vortex-test-installer (8.4)
- GitHub Check: vortex-test-installer (8.2)
- GitHub Check: vortex-test-installer (8.3)
- GitHub Check: vortex-test-docs
🔇 Additional comments (13)
.vortex/tests/bats/_helper.bash (1)
535-538: Allow generic '#;' comments; keep guard markers checks — good change.Permitting bare "#;" avoids false positives (e.g., in .gitignore), while still asserting "#;<" and "#;>" are stripped.
phpmd.xml (1)
17-18: Exclude Drupal recipes from PHPMD — sensible.Matches the new recipes/ install path and prevents noise from non-PHP application content.
composer.json (1)
133-135: Installer path for recipes at repo root — LGTM.Mapping type:drupal-recipe to recipes/{$name} aligns with tests and docs.
.gitignore (1)
34-34: Casing tweak for scaffold comment — looks good.tests/behat/features/search.feature (3)
11-14: LGTM: dataset now tests published vs draft.User story format and user type comply with guidelines; moderation_state/status columns are appropriate.
25-27: LGTM: assertions reflect published-only results.Draft is excluded; both published items present.
31-33: LGTM: scoped search result is correct.Unique term returns the expected single published item.
web/modules/custom/ys_search/config/install/search_api.index.content.yml (1)
61-68: LGTM: boolean status field mapping aligns with the view filter.Type, property_path, and dependencies look correct.
.vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
137-139: AllresolvedMessageoverrides and call sites updated
No instances of the old one-arg signature or one-argument calls remain—signature change fully applied..vortex/installer/tests/Unit/Handlers/StarterPromptManagerTest.php (1)
24-35: LGTM: adds DrupalCMS profile selection path and expectation.Covers selection order and ensures Profile is auto-resolved to the recipe path.
.vortex/installer/src/Prompts/Handlers/Webroot.php (2)
115-120: Signature alignment and behavior — LGTMMethod now matches HandlerInterface and mirrors Profile’s behavior. Message emission is correctly gated on string resolution.
115-120: All resolvedMessage handlers updated to the new signature
Verified thatHandlerInterface,AbstractHandler,Webroot, andProfileall declareresolvedMessage(array $responses, mixed $resolved): ?string..vortex/installer/src/Prompts/Handlers/Profile.php (1)
90-99: LGTM on resolved messaging.Resolved message reads well and is safe; minimal and consistent.
| 'starter, DrupalCMS profile' => [ | ||
| static::cw(fn() => Env::put(PromptManager::makeEnvName(Starter::id()), Starter::DRUPALCMS_INSTALL_PROFILE)), | ||
| static::cw(fn(FunctionalTestCase $test) => $test->assertSutNotContains([ | ||
| 'drupal/cms', | ||
| 'wikimedia/composer-merge-plugin', | ||
| 'vendor/drupal/cms/composer.json', | ||
| ])), | ||
| ], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Incorrect expectation for DrupalCMS path: packages should be present, not absent
For DRUPALCMS_INSTALL_PROFILE, Starter::process() adds drupal/cms, merge-plugin, and http-client to composer.json and wires merge-plugin. The test currently asserts they are absent, which is wrong.
Apply:
- 'starter, DrupalCMS profile' => [
- static::cw(fn() => Env::put(PromptManager::makeEnvName(Starter::id()), Starter::DRUPALCMS_INSTALL_PROFILE)),
- static::cw(fn(FunctionalTestCase $test) => $test->assertSutNotContains([
- 'drupal/cms',
- 'wikimedia/composer-merge-plugin',
- 'vendor/drupal/cms/composer.json',
- ])),
- ],
+ 'starter, DrupalCMS profile' => [
+ static::cw(fn() => Env::put(PromptManager::makeEnvName(Starter::id()), Starter::DRUPALCMS_INSTALL_PROFILE)),
+ static::cw(function (FunctionalTestCase $test) {
+ $composer = json_decode(file_get_contents(static::$sut . '/composer.json'), true);
+ $require = $composer['require'] ?? [];
+ $merge = $composer['extra']['merge-plugin'] ?? [];
+
+ $test->assertArrayHasKey('drupal/cms', $require);
+ $test->assertArrayHasKey('wikimedia/composer-merge-plugin', $require);
+ $test->assertArrayHasKey('symfony/http-client', $require);
+ $test->assertContains('vendor/drupal/cms/composer.json', $merge['require'] ?? []);
+ }),
+ ],📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| 'starter, DrupalCMS profile' => [ | |
| static::cw(fn() => Env::put(PromptManager::makeEnvName(Starter::id()), Starter::DRUPALCMS_INSTALL_PROFILE)), | |
| static::cw(fn(FunctionalTestCase $test) => $test->assertSutNotContains([ | |
| 'drupal/cms', | |
| 'wikimedia/composer-merge-plugin', | |
| 'vendor/drupal/cms/composer.json', | |
| ])), | |
| ], | |
| 'starter, DrupalCMS profile' => [ | |
| static::cw(fn() => Env::put(PromptManager::makeEnvName(Starter::id()), Starter::DRUPALCMS_INSTALL_PROFILE)), | |
| static::cw(function (FunctionalTestCase $test) { | |
| $composer = json_decode(file_get_contents(static::$sut . '/composer.json'), true); | |
| $require = $composer['require'] ?? []; | |
| $merge = $composer['extra']['merge-plugin'] ?? []; | |
| $test->assertArrayHasKey('drupal/cms', $require); | |
| $test->assertArrayHasKey('wikimedia/composer-merge-plugin', $require); | |
| $test->assertArrayHasKey('symfony/http-client', $require); | |
| $test->assertContains('vendor/drupal/cms/composer.json', $merge['require'] ?? []); | |
| }), | |
| ], |
🤖 Prompt for AI Agents
.vortex/installer/tests/Functional/Handlers/StarterInstallTest.php around lines
27-34: the test currently asserts that drupal/cms,
wikimedia/composer-merge-plugin, and vendor/drupal/cms/composer.json are absent
for the DRUPALCMS_INSTALL_PROFILE, but Starter::process() adds drupal/cms, the
merge-plugin, and http-client and wires the vendor/drupal/cms/composer.json;
change the assertion from assertSutNotContains to assertSutContains and ensure
the list includes 'drupal/cms', 'wikimedia/composer-merge-plugin',
'guzzlehttp/guzzle' (or the configured http-client package) and
'vendor/drupal/cms/composer.json' so the test expects those entries to be
present.
| # Assert all special comments were removed. | ||
| assert_dir_not_contains_string "${dir}" "#;" | ||
| # assert_dir_not_contains_string "${dir}" "#;" | ||
| assert_dir_not_contains_string "${dir}" "#;<" | ||
| assert_dir_not_contains_string "${dir}" "#;>" | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick (assertive)
Clarify the nearby comment to reflect intent.
Update wording so it’s clear we only enforce removal of VORTEX_DEV guard markers, not all "#;"-style comments.
- # Assert all special comments were removed.
+ # Assert VORTEX_DEV guard markers were removed.📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| # Assert all special comments were removed. | |
| assert_dir_not_contains_string "${dir}" "#;" | |
| # assert_dir_not_contains_string "${dir}" "#;" | |
| assert_dir_not_contains_string "${dir}" "#;<" | |
| assert_dir_not_contains_string "${dir}" "#;>" | |
| # Assert VORTEX_DEV guard markers were removed. | |
| # assert_dir_not_contains_string "${dir}" "#;" | |
| assert_dir_not_contains_string "${dir}" "#;<" | |
| assert_dir_not_contains_string "${dir}" "#;>" |
🤖 Prompt for AI Agents
.vortex/tests/bats/_helper.bash lines 534-538: The current comment "Assert all
special comments were removed." is ambiguous; change it to clearly state we are
only enforcing removal of VORTEX_DEV guard markers (the "#;<" and "#;>"
patterns), not every "#;"-style comment. Update the comment text to something
like "Assert VORTEX_DEV guard markers were removed (do not assert removal of all
'#;' comments)." so the intent matches the assertions below.
ca9fb1e to
91ca2f7
Compare
91ca2f7 to
f6913d4
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
.vortex/installer/src/Prompts/Handlers/Internal.php (1)
127-156: Guard response lookups to avoid undefined index notices.Directly indexing $responses risks notices when a handler didn’t run or was pre-resolved. Use null-coalescing on Starter/ProvisionType/DatabaseDownloadSource.
- if ($responses[Starter::id()] !== Starter::LOAD_DATABASE_DEMO) { + $starter = $responses[Starter::id()] ?? null; + if ($starter !== Starter::LOAD_DATABASE_DEMO) { $is_demo = FALSE; } // Check if it should be enabled based on the provision type and database // download source. - elseif ($responses[ProvisionType::id()] === ProvisionType::DATABASE) { + elseif (($responses[ProvisionType::id()] ?? null) === ProvisionType::DATABASE) { $db_file_exists = file_exists(Env::get('VORTEX_DB_DIR', './.data') . DIRECTORY_SEPARATOR . Env::get('VORTEX_DB_FILE', 'db.sql')); $has_comment = File::contains($this->dstDir . '/.env', 'Override project-specific values for demonstration purposes'); @@ - if ($responses[DatabaseDownloadSource::id()] === DatabaseDownloadSource::URL) { + if (($responses[DatabaseDownloadSource::id()] ?? null) === DatabaseDownloadSource::URL) { // For a downloading from URL, demo mode is enabled if the database // file does not exist or if there is an explicit comment in the // destination .env file that indicates that this is a demo mode. $is_demo = !$db_file_exists || $has_comment; } - elseif ($responses[DatabaseDownloadSource::id()] === DatabaseDownloadSource::CONTAINER_REGISTRY) { + elseif (($responses[DatabaseDownloadSource::id()] ?? null) === DatabaseDownloadSource::CONTAINER_REGISTRY) { // For a downloading from container registry, demo mode is enabled if // there is an explicit comment in the destination .env file that // indicates that this is a demo mode. $is_demo = $has_comment; }.vortex/tests/test.workflow.sh (1)
81-86: Swap Docker Compose and Drupal CMS tests in the default workflow
In.vortex/tests/test.workflow.sh(* )block, lines 81–86), reorder to runworkflow.docker-compose.batsbeforeworkflow.install.profile_drupalcms.bats:- bats "${TEST_DIR}"/bats/e2e/workflow.install.profile_drupalcms.bats - bats "${TEST_DIR}"/bats/e2e/workflow.docker-compose.bats + bats "${TEST_DIR}"/bats/e2e/workflow.docker-compose.bats + bats "${TEST_DIR}"/bats/e2e/workflow.install.profile_drupalcms.bats.vortex/installer/src/Prompts/Handlers/Starter.php (1)
128-140: Use strict comparison for response checks.Avoid loose equality on string enums.
- if ($this->response == self::LOAD_DATABASE_DEMO) { + if ($this->response === self::LOAD_DATABASE_DEMO) { @@ - elseif ($this->response == self::INSTALL_PROFILE_CORE || $this->response == self::INSTALL_PROFILE_DRUPALCMS) { + elseif ($this->response === self::INSTALL_PROFILE_CORE || $this->response === self::INSTALL_PROFILE_DRUPALCMS) {Also applies to: 133-140
♻️ Duplicate comments (18)
tests/behat/features/search.feature (2)
15-17: Batch the indexing steps to cut noise and speed up tests.Replace three per-node enqueue steps with one “queue all created” step.
- And I add the "page" content with the title "[TEST] Test page uniquestring" to the search index - And I add the "page" content with the title "[TEST] Test page otheruniquestring" to the search index - And I add the "page" content with the title "[TEST] Test page thirduniquestring" to the search index + And I queue all created "page" content for search indexing
19-19: Avoid fixed sleeps; wait for index readiness.Use a deterministic wait to reduce flakiness.
- And I wait for 5 seconds + And I wait for search indexing to complete#!/bin/bash # Find any remaining fixed sleeps in Behat features. rg -nP --glob 'tests/behat/**/*.feature' 'I wait for \d+\s+seconds'web/modules/custom/ys_search/config/install/search_api.index.content.yml (1)
61-68: Boolean “status” field added — good alignment with the View filter; plan update + reindex.Ensure this config lands on existing sites and trigger a full reindex to populate the new field.
#!/bin/bash # Deploy path (run on target env): # 1) Import config drush cim -y # 2) Clear and reindex the "content" index drush sapi-c drush sapi-i -y content # Verify "status" field exists on the index and documents are updated drush eval '$i=\Drupal::service("search_api.index_pool")->getIndex("content"); print_r(array_keys($i->getFields()));'web/modules/custom/ys_search/config/install/views.view.search.yml (2)
210-210: Switched to “teaser” view mode — verify every bundle has a teaser display.Prevent regressions where a bundle lacks teaser config.
#!/bin/bash # List teaser displays present in config; ensure all indexed bundles are covered. fd -a 'core.entity_view_display.node.*.teaser.yml' | sort
165-202: Remove redundant expose/group_info for a non-exposed boolean filter.YAML noise; keep only essentials for exposed: false.
status: id: status table: search_api_index_content field: status relationship: none group_type: group admin_label: '' plugin_id: search_api_boolean operator: '=' value: '1' group: 1 - exposed: false - expose: - operator_id: '' - label: '' - description: '' - use_operator: false - operator: '' - operator_limit_selection: false - operator_list: { } - identifier: '' - required: false - remember: false - multiple: false - remember_roles: - authenticated: authenticated - is_grouped: false - group_info: - label: '' - description: '' - identifier: '' - optional: true - widget: select - multiple: false - remember: false - default_group: All - default_group_multiple: { } - group_items: { } + exposed: false.vortex/tests/bats/_helper.bash (1)
534-538: Clarify the intent: only guard markers are enforced.Update the comment to reflect that we now assert only VORTEX_DEV guard markers (“#;<”/“#;>”), not every “#;”-style comment.
- # Assert all special comments were removed. + # Assert VORTEX_DEV guard markers were removed..vortex/installer/src/Prompts/Handlers/HandlerInterface.php (1)
143-146: Fix doc typos: handlerManager→PromptManager; handlering→prompting.- * This is used by handlerManager to show an appropriate message (via - * info(), ok(), etc.) when using a resolved value instead of handlering + * This is used by PromptManager to show an appropriate message (via + * info(), ok(), etc.) when using a resolved value instead of prompting.gitignore (1)
44-46: Keep the recipes directory via a .gitkeep exception.Add an exception so an empty recipes/ survives in new repos; commit recipes/.gitkeep.
# Ignore all recipes by default. Custom recipes should be added explicitly. recipes/* +!recipes/.gitkeepcomposer.json (1)
133-135: Add drupal-recipe to installer-types to activate this mapping.Without declaring "drupal-recipe" in extra.installer-types, oomphinc/composer-installers-extender won’t map type:drupal-recipe to recipes/{$name}.
"installer-types": [ "bower-asset", "npm-asset", - "drupal-library" + "drupal-library", + "drupal-recipe" ],Optional check:
#!/bin/bash rg -n '"type:drupal-recipe"|drupal-recipe' composer.json -n -C2.vortex/installer/tests/Functional/Handlers/StarterInstallTest.php (2)
14-15: Coverage annotation references the wrong class.This test manipulates Starter; update CoversClass accordingly.
-#[CoversClass(ProvisionType::class)] +#[CoversClass(Starter::class)]
27-34: Fix incorrect expectations: Drupal CMS composer entries should be present (not absent).Replace “not contains” directory scan with precise composer.json assertions, including http-client.
'starter, Drupal CMS profile' => [ static::cw(fn() => Env::put(PromptManager::makeEnvName(Starter::id()), Starter::INSTALL_PROFILE_DRUPALCMS)), - static::cw(fn(FunctionalTestCase $test) => $test->assertSutNotContains([ - 'drupal/cms', - 'wikimedia/composer-merge-plugin', - 'vendor/drupal/cms/composer.json', - ])), + static::cw(function (FunctionalTestCase $test) { + $composer = json_decode(file_get_contents(static::$sut . '/composer.json'), true); + $require = $composer['require'] ?? []; + $merge = $composer['extra']['merge-plugin'] ?? []; + + $test->assertArrayHasKey('drupal/cms', $require); + $test->assertArrayHasKey('wikimedia/composer-merge-plugin', $require); + $test->assertArrayHasKey('symfony/http-client', $require); + $test->assertContains('vendor/drupal/cms/composer.json', $merge['require'] ?? []); + }), ],.vortex/installer/src/Prompts/Handlers/Profile.php (2)
145-145: Anchor .env replacement to the DRUPAL_PROFILE line (defensive).Prevents accidental partial matches elsewhere in the file.
- File::replaceContentInFile($t . '/.env', '/DRUPAL_PROFILE=.*/', 'DRUPAL_PROFILE=' . $v); + File::replaceContentInFile($t . '/.env', '/^DRUPAL_PROFILE=.*/m', 'DRUPAL_PROFILE=' . $v);
147-149: Make contrib-path detection OS-agnostic.Current check fails if forward slashes are used on Windows.
- $is_contrib_profile = str_contains($v, DIRECTORY_SEPARATOR); + // Detect both Unix and Windows separators in provided path. + $is_contrib_profile = (strpbrk($v, '/\\') !== FALSE);.vortex/installer/src/Prompts/PromptManager.php (2)
166-167: Apply the same guard for Webroot logging.Mirror the Profile guard to avoid calling info(NULL).
- info($handler->resolvedMessage($r, $resolved)); + if ($m = $handler->resolvedMessage($r, $resolved)) { + info($m); + }
128-141: DRY the resolve/log/prompt flow with a helper.Both blocks duplicate resolve→optional-log→prompt fallback. Extract a helper for consistency.
Diff within these blocks:
- function (array $r, $pr, $n): string { - $handler = $this->handlers[Profile::id()]; - $resolved = $handler->resolvedValue($r); - if (is_string($resolved)) { - if ($m = $handler->resolvedMessage($r, $resolved)) { info($m); } - return $resolved; - } - else { - return (string) select(...$this->args(Profile::class)); - } - }, + fn(array $r, $pr, $n): string + => $this->resolveOrPrompt(Profile::id(), $r, fn() => (string) select(...$this->args(Profile::class))),- function (array $r, $pr, $n): string { - $handler = $this->handlers[Webroot::id()]; - $resolved = $handler->resolvedValue($r); - if (is_string($resolved)) { - if ($m = $handler->resolvedMessage($r, $resolved)) { info($m); } - return $resolved; - } - else { - return text(...$this->args(Webroot::class, NULL, $r)); - } - }, + fn(array $r, $pr, $n): string + => $this->resolveOrPrompt(Webroot::id(), $r, fn() => text(...$this->args(Webroot::class, NULL, $r))),Add this method to the class (outside the shown ranges):
private function resolveOrPrompt(string $id, array $r, callable $prompt): string { $handler = $this->handlers[$id]; $resolved = $handler->resolvedValue($r); if (is_string($resolved)) { if ($m = $handler->resolvedMessage($r, $resolved)) { info($m); } return $resolved; } return (string) $prompt(); }Also applies to: 161-174
.vortex/installer/src/Prompts/Handlers/Starter.php (3)
31-39: Align label to say “recipe” for Drupal CMS.Copy below already mentions “Drupal CMS recipe”; make the label match.
- $label2 = Tui::bold('Drupal CMS, installed from profile'); + $label2 = Tui::bold('Drupal CMS, installed from recipe');
69-72: Align option text with copy (“recipe” for Drupal CMS).- self::INSTALL_PROFILE_DRUPALCMS => 'Drupal CMS, installed from profile', + self::INSTALL_PROFILE_DRUPALCMS => 'Drupal CMS, installed from recipe',
93-115: Null-deref on missing composer.json; add installer-path and plugin allow; use strict compare.
- fromFile() can return NULL → fatal on addLink/addProperty.
- Recipes will install under vendor without installer-paths mapping.
- Composer 2 may block composer/installers without allow-plugins.
- Prefer strict equality.
- if ($this->response == self::INSTALL_PROFILE_DRUPALCMS) { - $cj = JsonManipulator::fromFile($this->tmpDir . '/composer.json'); + if ($this->response === self::INSTALL_PROFILE_DRUPALCMS) { + $composerPath = $this->tmpDir . '/composer.json'; + $cj = JsonManipulator::fromFile($composerPath); + if ($cj === NULL) { + throw new \RuntimeException(sprintf('composer.json not found or unreadable at %s', $composerPath)); + } $cj->addLink('require', 'drupal/cms', '^1.0', TRUE); $cj->addLink('require', 'wikimedia/composer-merge-plugin', '^2.1', TRUE); $cj->addLink('require', 'symfony/http-client', '^6.4 || ^7.0', TRUE); $cj->addConfigSetting('allow-plugins.drupal/core-project-message', TRUE); $cj->addConfigSetting('allow-plugins.wikimedia/composer-merge-plugin', TRUE); + $cj->addConfigSetting('allow-plugins.composer/installers', TRUE); $cj->addProperty('extra.merge-plugin.ignore-duplicates', FALSE); $cj->addProperty('extra.merge-plugin.merge-false', TRUE); $cj->addProperty('extra.merge-plugin.merge-extra', FALSE); $cj->addProperty('extra.merge-plugin.merge-extra-deep', FALSE); $cj->addProperty('extra.merge-plugin.merge-replace', TRUE); $cj->addProperty('extra.merge-plugin.merge-scripts', FALSE); $cj->addProperty('extra.merge-plugin.recurse', TRUE); $cj->addProperty('extra.merge-plugin.replace', TRUE); $cj->addProperty('extra.merge-plugin.require', ['vendor/drupal/cms/composer.json']); + $cj->addProperty('extra.installer-paths.web/recipes/{$name}', ['type:drupal-recipe']); - $c = $cj->getContents(); - file_put_contents($this->tmpDir . '/composer.json', $c); + $c = $cj->getContents(); + if (file_put_contents($composerPath, $c) === FALSE) { + throw new \RuntimeException(sprintf('Failed to write composer.json to %s', $composerPath)); + } }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (23)
.vortex/installer/tests/Fixtures/install/_baseline/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/_baseline/composer.jsonis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/_baseline/phpmd.xmlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/_baseline/tests/behat/features/search.featureis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/_baseline/web/modules/custom/sw_search/config/install/search_api.index.content.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/_baseline/web/modules/custom/sw_search/config/install/views.view.search.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/hosting_acquia/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/hosting_acquia/composer.jsonis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/hosting_acquia/docroot/modules/custom/sw_search/config/install/search_api.index.content.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/hosting_acquia/docroot/modules/custom/sw_search/config/install/views.view.search.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/hosting_acquia/phpmd.xmlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/names/web/modules/custom/the_force_search/config/install/search_api.index.content.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/names/web/modules/custom/the_force_search/config/install/views.view.search.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/starter_demo_db/.ignorecontentis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/starter_drupal_profile/.envis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/starter_drupalcms_profile/.envis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/starter_drupalcms_profile/composer.jsonis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/theme_absent/phpmd.xmlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/tools_groups_no_be_tests/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/tools_groups_no_be_tests_circleci/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/tools_no_phpunit/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/tools_no_phpunit_circleci/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/tools_none/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**
📒 Files selected for processing (19)
.gitignore(2 hunks).vortex/installer/src/Prompts/Handlers/AbstractHandler.php(1 hunks).vortex/installer/src/Prompts/Handlers/HandlerInterface.php(1 hunks).vortex/installer/src/Prompts/Handlers/Internal.php(1 hunks).vortex/installer/src/Prompts/Handlers/Profile.php(2 hunks).vortex/installer/src/Prompts/Handlers/Starter.php(6 hunks).vortex/installer/src/Prompts/Handlers/Webroot.php(1 hunks).vortex/installer/src/Prompts/PromptManager.php(2 hunks).vortex/installer/tests/Functional/Handlers/StarterInstallTest.php(1 hunks).vortex/installer/tests/Unit/Handlers/AbstractPromptManagerTestCase.php(1 hunks).vortex/installer/tests/Unit/Handlers/StarterPromptManagerTest.php(2 hunks).vortex/tests/bats/_helper.bash(1 hunks).vortex/tests/bats/e2e/workflow.install.profile_drupalcms.bats(1 hunks).vortex/tests/test.workflow.sh(2 hunks)composer.json(1 hunks)phpmd.xml(1 hunks)tests/behat/features/search.feature(1 hunks)web/modules/custom/ys_search/config/install/search_api.index.content.yml(1 hunks)web/modules/custom/ys_search/config/install/views.view.search.yml(1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
composer.json
📄 CodeRabbit inference engine (CLAUDE.md)
When adding JavaScript or CSS libraries as Drupal libraries with Composer, define them as inline Composer packages in the 'repositories' section of composer.json
Files:
composer.json
tests/behat/**/*.feature
📄 CodeRabbit inference engine (CLAUDE.md)
tests/behat/**/*.feature: All Behat feature files must use the standard user story format: 'As a [user type]\nI want to [action]\nSo that [benefit]'
Use consistent user types in Behat feature files: 'site visitor', 'site administrator', and 'content editor'
Do not use commas or periods in user story statements within Behat feature files
Files:
tests/behat/features/search.feature
web/modules/custom/**
📄 CodeRabbit inference engine (CLAUDE.md)
Custom modules should be placed in 'web/modules/custom/'
Files:
web/modules/custom/ys_search/config/install/search_api.index.content.ymlweb/modules/custom/ys_search/config/install/views.view.search.yml
🧠 Learnings (1)
📚 Learning: 2025-08-08T12:02:24.652Z
Learnt from: AlexSkrypnyk
PR: drevops/vortex#1896
File: .vortex/tests/bats/unit/download-db-lagoon.bats:24-25
Timestamp: 2025-08-08T12:02:24.652Z
Learning: In .vortex/tests/bats/unit Bats tests using ../_helper.bash (run_steps), prefixing a STEPS entry with "- " denotes a negative assertion (the substring must NOT appear in output). Unprefixed entries are positive assertions. Example: "- Database dump refresh requested. Will create a new dump." asserts absence; "Database dump refresh requested. Will create a new dump." asserts presence.
Applied to files:
.vortex/tests/test.workflow.sh.vortex/tests/bats/e2e/workflow.install.profile_drupalcms.bats.vortex/tests/bats/_helper.bash
🧬 Code graph analysis (12)
.vortex/installer/tests/Unit/Handlers/AbstractPromptManagerTestCase.php (1)
.vortex/installer/src/Prompts/Handlers/Starter.php (1)
Starter(10-150)
.vortex/installer/src/Prompts/Handlers/Internal.php (3)
.vortex/installer/src/Prompts/Handlers/Starter.php (1)
Starter(10-150).vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
id(52-62).vortex/installer/src/Prompts/Handlers/HandlerInterface.php (1)
id(19-19)
.vortex/tests/test.workflow.sh (3)
.vortex/tests/test.common.sh (1)
bats(28-37).vortex/tests/test.deployment.sh (1)
bats(29-38).vortex/tests/test.postbuild.sh (1)
bats(20-29)
.vortex/tests/bats/e2e/workflow.install.profile_drupalcms.bats (2)
.vortex/tests/bats/_helper.workflow.bash (6)
prepare_sut(7-39)assert_ahoy_build(73-130)assert_gitignore(132-162)assert_ahoy_lint(413-425)assert_ahoy_test(527-544)assert_ahoy_fe(753-777).vortex/tests/bats/_helper.bash (1)
assert_webpage_contains(1022-1028)
.vortex/installer/src/Prompts/Handlers/Webroot.php (3)
.vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
resolvedMessage(137-139).vortex/installer/src/Prompts/Handlers/HandlerInterface.php (1)
resolvedMessage(155-155).vortex/installer/src/Prompts/Handlers/Profile.php (1)
resolvedMessage(93-99)
.vortex/installer/src/Prompts/Handlers/HandlerInterface.php (3)
.vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
resolvedMessage(137-139).vortex/installer/src/Prompts/Handlers/Profile.php (1)
resolvedMessage(93-99).vortex/installer/src/Prompts/Handlers/Webroot.php (1)
resolvedMessage(115-121)
.vortex/installer/tests/Functional/Handlers/StarterInstallTest.php (8)
.vortex/installer/src/Prompts/Handlers/ProvisionType.php (1)
ProvisionType(11-103).vortex/installer/src/Prompts/Handlers/Starter.php (1)
Starter(10-150).vortex/installer/src/Prompts/PromptManager.php (2)
PromptManager(58-581)makeEnvName(431-433).vortex/installer/src/Utils/Env.php (2)
Env(7-245)put(24-26).vortex/installer/tests/Unit/Handlers/StarterPromptManagerTest.php (1)
CoversClass(12-47).vortex/installer/tests/Functional/Handlers/AbstractInstallTestCase.php (1)
AbstractInstallTestCase(19-101).vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
id(52-62).vortex/installer/tests/Functional/FunctionalTestCase.php (1)
assertSutNotContains(139-154)
.vortex/installer/src/Prompts/PromptManager.php (4)
.vortex/installer/src/Prompts/Handlers/Profile.php (3)
Profile(10-165)resolvedValue(76-88)resolvedMessage(93-99).vortex/installer/src/Prompts/Handlers/AbstractHandler.php (3)
id(52-62)resolvedValue(130-132)resolvedMessage(137-139).vortex/installer/src/Prompts/Handlers/Webroot.php (2)
resolvedValue(98-110)resolvedMessage(115-121).vortex/installer/src/Utils/Tui.php (1)
info(42-44)
.vortex/installer/tests/Unit/Handlers/StarterPromptManagerTest.php (4)
.vortex/installer/src/Prompts/Handlers/Profile.php (1)
Profile(10-165).vortex/installer/src/Prompts/Handlers/Starter.php (1)
Starter(10-150).vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
id(52-62).vortex/installer/src/Prompts/Handlers/HandlerInterface.php (1)
id(19-19)
.vortex/installer/src/Prompts/Handlers/AbstractHandler.php (3)
.vortex/installer/src/Prompts/Handlers/HandlerInterface.php (1)
resolvedMessage(155-155).vortex/installer/src/Prompts/Handlers/Profile.php (1)
resolvedMessage(93-99).vortex/installer/src/Prompts/Handlers/Webroot.php (1)
resolvedMessage(115-121)
.vortex/installer/src/Prompts/Handlers/Starter.php (2)
.vortex/installer/src/Utils/JsonManipulator.php (2)
JsonManipulator(10-76)fromFile(19-36).vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
AbstractHandler(10-233)
.vortex/installer/src/Prompts/Handlers/Profile.php (6)
.vortex/installer/src/Prompts/Handlers/AbstractHandler.php (4)
resolvedValue(130-132)id(52-62)resolvedMessage(137-139)getResponseAsString(191-197).vortex/installer/src/Prompts/Handlers/HandlerInterface.php (3)
resolvedValue(138-138)id(19-19)resolvedMessage(155-155).vortex/installer/src/Prompts/Handlers/Webroot.php (4)
resolvedValue(98-110)discover(65-79)resolvedMessage(115-121)process(126-146).vortex/installer/src/Prompts/Handlers/Starter.php (1)
Starter(10-150).vortex/installer/src/Prompts/Handlers/ProfileCustom.php (1)
ProfileCustom(9-86).vortex/installer/src/Utils/File.php (2)
File(10-102)replaceContentAsync(59-83)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (12)
- GitHub Check: build (0)
- GitHub Check: build (1)
- GitHub Check: vortex-test-deployment (1)
- GitHub Check: vortex-test-workflow (2)
- GitHub Check: vortex-test-deployment (0)
- GitHub Check: vortex-test-workflow (0)
- GitHub Check: vortex-test-workflow (1)
- GitHub Check: vortex-test-workflow (3)
- GitHub Check: vortex-test-common
- GitHub Check: vortex-test-installer (8.2)
- GitHub Check: vortex-test-installer (8.4)
- GitHub Check: vortex-test-installer (8.3)
🔇 Additional comments (15)
tests/behat/features/search.feature (2)
11-14: Dataset aligns with moderation-aware search — LGTM.Using status + moderation_state is consistent with the new boolean status filter.
25-27: Moderation-aware assertions — LGTM.Correctly ensures drafts are excluded and published items are visible.
Also applies to: 31-33
phpmd.xml (1)
17-18: Exclude recipes from PHPMD — correct scope.Good call adding the recipes exclude; the glob will cover both top-level “recipes/” and potential “web/recipes/”.
.vortex/installer/src/Prompts/Handlers/HandlerInterface.php (1)
149-156: ResolvedMessage signature is consistent across all Handler implementations.
Verified no class definesresolvedMessagewith the old one-argument signature; all inherit or override it asresolvedMessage(array $responses, mixed $resolved): ?string..gitignore (1)
34-34: Wording LGTM..vortex/tests/test.workflow.sh (1)
73-73: LGTM: added Drupal CMS e2e shard.The new workflow.install.profile_drupalcms.bats invocation in case 3 is correctly wired after docker-compose.
.vortex/installer/tests/Unit/Handlers/AbstractPromptManagerTestCase.php (1)
124-124: LGTM: default updated to LOAD_DATABASE_DEMO.Default mapping reflects the new Starter constants.
.vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
137-139: Update allresolvedMessageoverrides and call sites
The method signature now requiresmixed $resolved; verify every handler override and caller passes the new parameter..vortex/installer/src/Prompts/Handlers/Webroot.php (1)
115-118: LGTM: resolvedMessage uses the resolved value safely.Message emits only when $resolved is a string; consistent with new contract.
.vortex/installer/tests/Unit/Handlers/StarterPromptManagerTest.php (1)
7-7: LGTM: unit test updates align with new Starter/Profile flow.
- Importing Profile is correct.
- Defaults and selection expectations match new constants.
- Drupal CMS case properly asserts resolved Profile path.
Also applies to: 21-21, 24-27, 28-34, 39-39
.vortex/tests/bats/e2e/workflow.install.profile_drupalcms.bats (1)
24-27: Verify symfony/http-client assertion
I couldn’t locate whereStarter::processadds thesymfony/http-clientpackage. Please confirm that the install step now includes this dependency and, if so, extend the Bats test at.vortex/tests/bats/e2e/workflow.install.profile_drupalcms.bats(lines 24–27):assert_file_contains composer.json "vendor/drupal/cms/composer.json" +assert_file_contains composer.json "symfony/http-client".vortex/installer/src/Prompts/Handlers/Profile.php (1)
76-88: Overall: new resolution + processing logic looks correct.
- resolvedValue bridges Drupal CMS starter selection to Profile path.
- Process handles custom and contrib profiles as expected (post-anchors/OS fix applied).
Also applies to: 131-163
.vortex/installer/src/Prompts/Handlers/Starter.php (3)
7-7: Import looks correct.JsonManipulator usage is appropriate for composer.json mutation.
12-19: Constants/readability LGTM.Names are clear; path matches Profile::resolvedValue usage.
79-80: Default choice LGTM.LOAD_DATABASE_DEMO as default matches tests and first-run UX.
f6913d4 to
fff572d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 7
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
.vortex/installer/src/Prompts/Handlers/Internal.php (1)
127-131: Use null-safe access for Starter response to avoid undefined indexMinor hardening: guard when Starter response is absent in edge flows (e.g., pre-resolution paths).
Apply:
- if ($responses[Starter::id()] !== Starter::LOAD_DATABASE_DEMO) { + $starter = $responses[Starter::id()] ?? null; + if ($starter !== Starter::LOAD_DATABASE_DEMO) { $is_demo = FALSE; }.vortex/installer/src/Prompts/Handlers/Profile.php (1)
30-32: Hint text: select uses Enter, not Space bar.Minor UX copy fix.
- return 'Use ⬆, ⬇ and Space bar to select which Drupal profile to use.'; + return 'Use ⬆ and ⬇ to select a Drupal profile, then press Enter.';.vortex/installer/src/Prompts/Handlers/Starter.php (1)
128-140: Use strict comparison in postInstall.
Avoid loose comparisons for clarity and safety.- if ($this->response == self::LOAD_DATABASE_DEMO) { + if ($this->response === self::LOAD_DATABASE_DEMO) { @@ - elseif ($this->response == self::INSTALL_PROFILE_CORE || $this->response == self::INSTALL_PROFILE_DRUPALCMS) { + elseif ($this->response === self::INSTALL_PROFILE_CORE || $this->response === self::INSTALL_PROFILE_DRUPALCMS) {
♻️ Duplicate comments (17)
web/modules/custom/ys_search/config/install/search_api.index.content.yml (1)
61-69: Plan a config update + reindex for existing sites.This change in config/install won’t auto-apply to sites already installed. Add a post-update (or deploy runbook) to import the updated index config and trigger a full reindex (e.g., drush cim -y && drush sapi-c && drush sapi-i -y content).
tests/behat/features/search.feature (2)
15-17: Batch indexing to reduce noise and time.Prefer a single step to enqueue all created pages for indexing if available.
Apply:
- And I add the "page" content with the title "[TEST] Test page uniquestring" to the search index - And I add the "page" content with the title "[TEST] Test page otheruniquestring" to the search index - And I add the "page" content with the title "[TEST] Test page thirduniquestring" to the search index + And I queue all created "page" content for search indexing
19-20: Replace fixed sleep with deterministic wait.Poll for index readiness instead of sleeping to cut flakiness.
- And I wait for 5 seconds - And I visit "/search" + And I wait for search indexing to complete + And I visit "/search"web/modules/custom/ys_search/config/install/views.view.search.yml (2)
210-210: Switch to teaser view mode — verify bundle displays.Confirm every indexed bundle has a configured “teaser” display with intended fields; otherwise adjust.
176-202: Trim redundant expose/group blocks for a non-exposed filter.Since exposed: false, the expose and group_info subtrees add noise.
exposed: false - expose: - operator_id: '' - label: '' - description: '' - use_operator: false - operator: '' - operator_limit_selection: false - operator_list: { } - identifier: '' - required: false - remember: false - multiple: false - remember_roles: - authenticated: authenticated is_grouped: false - group_info: - label: '' - description: '' - identifier: '' - optional: true - widget: select - multiple: false - remember: false - default_group: All - default_group_multiple: { } - group_items: { }.vortex/tests/bats/_helper.bash (1)
534-538: Clarify intent: only enforce VORTEX_DEV guard markers, not generic '#;' comments.Keep the relaxed assertion but fix the misleading comment to avoid confusion.
- # Assert all special comments were removed. - # assert_dir_not_contains_string "${dir}" "#;" + # Assert VORTEX_DEV guard markers were removed (do not assert removal of all '#;' comments). + # NOTE: Generic '#;' comments are allowed; only '#;<' and '#;>' markers are enforced. assert_dir_not_contains_string "${dir}" "#;<" assert_dir_not_contains_string "${dir}" "#;>"composer.json (1)
133-135: Mapping alone won’t take effect without declaring the type. Add "drupal-recipe" to installer-types.oomphinc/composer-installers-extender requires the custom type to be listed in extra.installer-types; otherwise packages of type "drupal-recipe" won’t install to recipes/{$name}.
"installer-types": [ "bower-asset", "npm-asset", - "drupal-library" + "drupal-library", + "drupal-recipe" ],.vortex/installer/src/Prompts/Handlers/HandlerInterface.php (1)
143-156: Fix doc typos and align with the actual manager name.Use “PromptManager” and “prompting”; keep the new $resolved param as is.
- * This is used by handlerManager to show an appropriate message (via - * info(), ok(), etc.) when using a resolved value instead of handlering + * This is used by PromptManager to show an appropriate message (via + * info(), ok(), etc.) when using a resolved value instead of prompting * for input.To verify all implementers accept the new $resolved param:
#!/bin/bash # Find implementations missing the $resolved param rg -nP --type=php '(?s)implements\s+HandlerInterface.*?\bfunction\s+resolvedMessage\s*\(\s*array\s+\$responses\s*\)' -C2 .vortex/installer.gitignore (1)
44-46: Optional: keep the recipes directory present with a tracked placeholder.If you want an empty recipes/ directory in fresh clones, allow a keep file.
# Ignore all recipes by default. Custom recipes should be added explicitly. recipes/* +!recipes/.gitkeepIf .gitkeep (or similar) is already tracked, this change is not required.
.vortex/tests/bats/e2e/workflow.install.profile_drupalcms.bats (2)
16-16: Fix env value: must match Starter option key, not aliasUse the canonical option key so the non-interactive selection is applied.
Apply this diff:
- export VORTEX_INSTALLER_PROMPT_STARTER="drupalcms_profile" + export VORTEX_INSTALLER_PROMPT_STARTER="install_profile_drupalcms"
39-40: Add teardown to prevent env leakage across testsUnset env vars set by this test to avoid cross-test interference.
Apply this diff:
assert_webpage_contains "/" "This is the home page of your new site." } +teardown() { + unset VORTEX_INSTALLER_PROMPT_STARTER VORTEX_INSTALLER_IS_DEMO_DB_DOWNLOAD_SKIP +}.vortex/installer/tests/Functional/Handlers/StarterInstallTest.php (2)
14-15: Fix coverage subject: this test targets Starter, not ProvisionType.Align the CoversClass to the handler under test.
-#[CoversClass(ProvisionType::class)] +#[CoversClass(Starter::class)]
27-34: Incorrect expectation: Drupal CMS deps should be present, not absent.Starter::process() adds drupal/cms, composer-merge-plugin, symfony/http-client and wires merge-plugin. Assert presence with a composer.json read.
- 'starter, Drupal CMS profile' => [ - static::cw(fn() => Env::put(PromptManager::makeEnvName(Starter::id()), Starter::INSTALL_PROFILE_DRUPALCMS)), - static::cw(fn(FunctionalTestCase $test) => $test->assertSutNotContains([ - 'drupal/cms', - 'wikimedia/composer-merge-plugin', - 'vendor/drupal/cms/composer.json', - ])), - ], + 'starter, Drupal CMS profile' => [ + static::cw(fn() => Env::put(PromptManager::makeEnvName(Starter::id()), Starter::INSTALL_PROFILE_DRUPALCMS)), + static::cw(function (FunctionalTestCase $test): void { + $composer = json_decode(file_get_contents(static::$sut . '/composer.json'), true, flags: JSON_THROW_ON_ERROR); + $require = $composer['require'] ?? []; + $merge = $composer['extra']['merge-plugin'] ?? []; + + $test->assertArrayHasKey('drupal/cms', $require); + $test->assertArrayHasKey('wikimedia/composer-merge-plugin', $require); + $test->assertArrayHasKey('symfony/http-client', $require); + $test->assertContains('vendor/drupal/cms/composer.json', $merge['require'] ?? []); + }), + ],.vortex/installer/src/Prompts/Handlers/Profile.php (2)
145-146: Anchor DRUPAL_PROFILE replacement to the line (defensive).Prevents accidental matches elsewhere in .env.
- File::replaceContentInFile($t . '/.env', '/DRUPAL_PROFILE=.*/', 'DRUPAL_PROFILE=' . $v); + File::replaceContentInFile($t . '/.env', '/^DRUPAL_PROFILE=.*/m', 'DRUPAL_PROFILE=' . $v);
147-149: Cross-OS path check: detect both '/' and ''.str_contains with DIRECTORY_SEPARATOR misses Unix-style paths on Windows.
- // Assume that profiles provided as a path are contrib profiles. - $is_contrib_profile = str_contains($v, DIRECTORY_SEPARATOR); + // Assume that profiles provided as a path are contrib profiles. + // Detect both Unix and Windows separators. + $is_contrib_profile = (strpbrk($v, '/\\') !== FALSE);.vortex/installer/src/Prompts/Handlers/Starter.php (2)
31-39: Align labels with copy (“Drupal CMS”, “recipe”).
Update labels to match the agreed wording.- $label1 = Tui::bold('Drupal, installed from profile'); + $label1 = Tui::bold('Drupal, installed from recipe'); @@ - $label2 = Tui::bold('Drupal CMS, installed from profile'); + $label2 = Tui::bold('Drupal CMS, installed from recipe'); @@ - $label3 = Tui::bold('Drupal, loaded from the demo database'); + $label3 = Tui::bold('Drupal CMS, loaded from the demo database');
69-72: Align option labels with copy (“Drupal CMS”, “recipe”).
Mirror the label changes in the options.- self::INSTALL_PROFILE_CORE => 'Drupal, installed from profile', - self::INSTALL_PROFILE_DRUPALCMS => 'Drupal CMS, installed from profile', - self::LOAD_DATABASE_DEMO => 'Drupal, loaded from the demo database', + self::INSTALL_PROFILE_CORE => 'Drupal, installed from recipe', + self::INSTALL_PROFILE_DRUPALCMS => 'Drupal CMS, installed from recipe', + self::LOAD_DATABASE_DEMO => 'Drupal CMS, loaded from the demo database',
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (23)
.vortex/installer/tests/Fixtures/install/_baseline/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/_baseline/composer.jsonis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/_baseline/phpmd.xmlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/_baseline/tests/behat/features/search.featureis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/_baseline/web/modules/custom/sw_search/config/install/search_api.index.content.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/_baseline/web/modules/custom/sw_search/config/install/views.view.search.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/hosting_acquia/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/hosting_acquia/composer.jsonis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/hosting_acquia/docroot/modules/custom/sw_search/config/install/search_api.index.content.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/hosting_acquia/docroot/modules/custom/sw_search/config/install/views.view.search.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/hosting_acquia/phpmd.xmlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/names/web/modules/custom/the_force_search/config/install/search_api.index.content.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/names/web/modules/custom/the_force_search/config/install/views.view.search.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/starter_demo_db/.ignorecontentis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/starter_drupal_cms_profile/.envis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/starter_drupal_cms_profile/composer.jsonis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/starter_drupal_profile/.envis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/theme_absent/phpmd.xmlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/tools_groups_no_be_tests/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/tools_groups_no_be_tests_circleci/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/tools_no_phpunit/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/tools_no_phpunit_circleci/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/tools_none/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**
📒 Files selected for processing (19)
.gitignore(2 hunks).vortex/installer/src/Prompts/Handlers/AbstractHandler.php(1 hunks).vortex/installer/src/Prompts/Handlers/HandlerInterface.php(1 hunks).vortex/installer/src/Prompts/Handlers/Internal.php(1 hunks).vortex/installer/src/Prompts/Handlers/Profile.php(2 hunks).vortex/installer/src/Prompts/Handlers/Starter.php(6 hunks).vortex/installer/src/Prompts/Handlers/Webroot.php(1 hunks).vortex/installer/src/Prompts/PromptManager.php(3 hunks).vortex/installer/tests/Functional/Handlers/StarterInstallTest.php(1 hunks).vortex/installer/tests/Unit/Handlers/AbstractPromptManagerTestCase.php(1 hunks).vortex/installer/tests/Unit/Handlers/StarterPromptManagerTest.php(2 hunks).vortex/tests/bats/_helper.bash(1 hunks).vortex/tests/bats/e2e/workflow.install.profile_drupalcms.bats(1 hunks).vortex/tests/test.workflow.sh(2 hunks)composer.json(1 hunks)phpmd.xml(1 hunks)tests/behat/features/search.feature(1 hunks)web/modules/custom/ys_search/config/install/search_api.index.content.yml(1 hunks)web/modules/custom/ys_search/config/install/views.view.search.yml(1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
tests/behat/**/*.feature
📄 CodeRabbit inference engine (CLAUDE.md)
tests/behat/**/*.feature: All Behat feature files must use the standard user story format: 'As a [user type]\nI want to [action]\nSo that [benefit]'
Use consistent user types in Behat feature files: 'site visitor', 'site administrator', and 'content editor'
Do not use commas or periods in user story statements within Behat feature files
Files:
tests/behat/features/search.feature
web/modules/custom/**
📄 CodeRabbit inference engine (CLAUDE.md)
Custom modules should be placed in 'web/modules/custom/'
Files:
web/modules/custom/ys_search/config/install/views.view.search.ymlweb/modules/custom/ys_search/config/install/search_api.index.content.yml
composer.json
📄 CodeRabbit inference engine (CLAUDE.md)
When adding JavaScript or CSS libraries as Drupal libraries with Composer, define them as inline Composer packages in the 'repositories' section of composer.json
Files:
composer.json
🧠 Learnings (1)
📚 Learning: 2025-08-08T12:02:24.652Z
Learnt from: AlexSkrypnyk
PR: drevops/vortex#1896
File: .vortex/tests/bats/unit/download-db-lagoon.bats:24-25
Timestamp: 2025-08-08T12:02:24.652Z
Learning: In .vortex/tests/bats/unit Bats tests using ../_helper.bash (run_steps), prefixing a STEPS entry with "- " denotes a negative assertion (the substring must NOT appear in output). Unprefixed entries are positive assertions. Example: "- Database dump refresh requested. Will create a new dump." asserts absence; "Database dump refresh requested. Will create a new dump." asserts presence.
Applied to files:
.vortex/tests/bats/e2e/workflow.install.profile_drupalcms.bats.vortex/tests/bats/_helper.bash.vortex/tests/test.workflow.sh
🧬 Code graph analysis (12)
.vortex/tests/bats/e2e/workflow.install.profile_drupalcms.bats (2)
.vortex/tests/bats/_helper.workflow.bash (6)
prepare_sut(7-39)assert_ahoy_build(73-130)assert_gitignore(132-162)assert_ahoy_lint(413-425)assert_ahoy_test(527-544)assert_ahoy_fe(753-777).vortex/tests/bats/_helper.bash (1)
assert_webpage_contains(1022-1028)
.vortex/installer/tests/Unit/Handlers/StarterPromptManagerTest.php (4)
.vortex/installer/src/Prompts/Handlers/Profile.php (1)
Profile(10-165).vortex/installer/src/Prompts/Handlers/Starter.php (1)
Starter(10-150).vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
id(52-62).vortex/installer/src/Prompts/Handlers/HandlerInterface.php (1)
id(19-19)
.vortex/installer/src/Prompts/Handlers/Internal.php (3)
.vortex/installer/src/Prompts/Handlers/Starter.php (1)
Starter(10-150).vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
id(52-62).vortex/installer/src/Prompts/Handlers/HandlerInterface.php (1)
id(19-19)
.vortex/installer/src/Prompts/Handlers/Webroot.php (3)
.vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
resolvedMessage(137-139).vortex/installer/src/Prompts/Handlers/HandlerInterface.php (1)
resolvedMessage(155-155).vortex/installer/src/Prompts/Handlers/Profile.php (1)
resolvedMessage(93-99)
.vortex/installer/src/Prompts/Handlers/AbstractHandler.php (3)
.vortex/installer/src/Prompts/Handlers/HandlerInterface.php (1)
resolvedMessage(155-155).vortex/installer/src/Prompts/Handlers/Profile.php (1)
resolvedMessage(93-99).vortex/installer/src/Prompts/Handlers/Webroot.php (1)
resolvedMessage(115-121)
.vortex/installer/tests/Functional/Handlers/StarterInstallTest.php (7)
.vortex/installer/src/Prompts/Handlers/ProvisionType.php (1)
ProvisionType(11-103).vortex/installer/src/Prompts/Handlers/Starter.php (1)
Starter(10-150).vortex/installer/src/Prompts/PromptManager.php (2)
PromptManager(58-597)makeEnvName(413-415).vortex/installer/src/Utils/Env.php (2)
Env(7-245)put(24-26).vortex/installer/tests/Unit/Handlers/StarterPromptManagerTest.php (1)
CoversClass(12-47).vortex/installer/tests/Functional/Handlers/AbstractInstallTestCase.php (1)
AbstractInstallTestCase(19-101).vortex/installer/tests/Functional/FunctionalTestCase.php (1)
assertSutNotContains(139-154)
.vortex/installer/src/Prompts/Handlers/HandlerInterface.php (3)
.vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
resolvedMessage(137-139).vortex/installer/src/Prompts/Handlers/Profile.php (1)
resolvedMessage(93-99).vortex/installer/src/Prompts/Handlers/Webroot.php (1)
resolvedMessage(115-121)
.vortex/installer/src/Prompts/PromptManager.php (7)
.vortex/installer/src/Prompts/Handlers/Profile.php (3)
Profile(10-165)resolvedValue(76-88)resolvedMessage(93-99).vortex/installer/src/Prompts/Handlers/AbstractHandler.php (3)
id(52-62)resolvedValue(130-132)resolvedMessage(137-139).vortex/installer/src/Prompts/Handlers/HandlerInterface.php (3)
id(19-19)resolvedValue(138-138)resolvedMessage(155-155).vortex/installer/src/Prompts/Handlers/Webroot.php (3)
Webroot(12-148)resolvedValue(98-110)resolvedMessage(115-121).vortex/installer/src/Utils/Tui.php (1)
info(42-44)scripts/custom/provision-10-example.sh (1)
info(22-22)scripts/vortex/update-vortex.sh (1)
info(46-46)
.vortex/installer/tests/Unit/Handlers/AbstractPromptManagerTestCase.php (1)
.vortex/installer/src/Prompts/Handlers/Starter.php (1)
Starter(10-150)
.vortex/tests/test.workflow.sh (3)
.vortex/tests/test.common.sh (1)
bats(28-37).vortex/tests/test.postbuild.sh (1)
bats(20-29).vortex/tests/test.deployment.sh (1)
bats(29-38)
.vortex/installer/src/Prompts/Handlers/Starter.php (3)
.vortex/installer/src/Utils/JsonManipulator.php (2)
JsonManipulator(10-76)fromFile(19-36).vortex/installer/src/Utils/Tui.php (3)
Tui(15-233)bold(74-76)underscore(78-80).vortex/installer/src/Prompts/Handlers/AbstractHandler.php (2)
AbstractHandler(10-233)default(109-111)
.vortex/installer/src/Prompts/Handlers/Profile.php (4)
.vortex/installer/src/Prompts/Handlers/AbstractHandler.php (4)
resolvedValue(130-132)id(52-62)resolvedMessage(137-139)getResponseAsString(191-197).vortex/installer/src/Prompts/Handlers/Starter.php (1)
Starter(10-150).vortex/installer/src/Prompts/Handlers/ProfileCustom.php (1)
ProfileCustom(9-86).vortex/installer/src/Utils/File.php (2)
File(10-102)replaceContentAsync(59-83)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (13)
- GitHub Check: build (0)
- GitHub Check: build (1)
- GitHub Check: vortex-test-workflow (3)
- GitHub Check: vortex-test-deployment (0)
- GitHub Check: vortex-test-workflow (0)
- GitHub Check: vortex-test-workflow (2)
- GitHub Check: vortex-test-workflow (1)
- GitHub Check: vortex-test-deployment (1)
- GitHub Check: vortex-test-common
- GitHub Check: vortex-test-installer (8.2)
- GitHub Check: vortex-test-installer (8.4)
- GitHub Check: vortex-test-installer (8.3)
- GitHub Check: vortex-test-docs
🔇 Additional comments (19)
web/modules/custom/ys_search/config/install/search_api.index.content.yml (1)
61-65: LGTM: boolean Published field added to the index mapping.The status mapping (property_path: status, type: boolean) is correct and aligns with the view’s boolean filter.
tests/behat/features/search.feature (3)
11-14: Data schema update (status + moderation_state) — OK.The table structure is sound and matches the published/draft expectations.
25-27: Assertions match published-only behavior — OK.
31-33: Scoped query assertions — OK.web/modules/custom/ys_search/config/install/views.view.search.yml (1)
165-175: LGTM: Published-only filter added.Filter configuration (plugin_id: search_api_boolean, value: '1') matches the index’s boolean status field.
phpmd.xml (1)
17-18: LGTM: exclude Drupal recipes from PHPMD.The new exclude-pattern correctly skips recipes. No further changes needed.
.gitignore (1)
34-34: LGTM: clarify scaffold allowance.Comment reads well and matches project conventions.
.vortex/installer/tests/Unit/Handlers/AbstractPromptManagerTestCase.php (1)
124-125: No stale legacy constants found
Ran a project-wide search forDRUPAL_LOAD_DATABASE_DEMOandDRUPAL_INSTALL_PROFILEoutside ofvendor/; no matches were found..vortex/installer/src/Prompts/Handlers/Webroot.php (1)
115-117: Signature alignment and message logic look correctThe handler now cleanly uses the resolved value threaded by PromptManager and guards on string type. Consistent with Profile::resolvedMessage.
.vortex/installer/tests/Unit/Handlers/StarterPromptManagerTest.php (4)
7-7: Import added is necessary for expectations on Profile::id()This fixes static resolution for the new profile expectation keys.
21-21: Updated default expectation matches new constantSwitch to LOAD_DATABASE_DEMO aligns with Starter::default().
24-27: Verify keystroke path matches options order/default selectionGiven options order (Core, Drupal CMS, Demo) and default set to LOAD_DATABASE_DEMO, confirm Laravel Prompts starts the cursor on the default and how DOWN behaves (wrap vs. move). Otherwise this case may select the wrong item.
28-34: Add case looks good; confirm DOWN count maps to Drupal CMSSame caveat: ensure two DOWNs from the initial position deterministically select INSTALL_PROFILE_DRUPALCMS in your prompt harness.
.vortex/installer/src/Prompts/PromptManager.php (2)
128-131: Good use of resolveOrPrompt for Profile.Removes duplication and centralizes resolved-message logging.
153-154: Good: Webroot resolution also centralized..vortex/installer/src/Prompts/Handlers/Profile.php (1)
76-88: LGTM: Profile auto-resolves when Starter selects Drupal CMS.Clean separation via resolvedValue/resolvedMessage.
.vortex/installer/src/Prompts/Handlers/Starter.php (3)
7-7: Import looks good.
JsonManipulator import is appropriate for composer.json mutations.
78-80: Default selection change LGTM.
Choosing demo DB by default aligns with “first run” guidance.
103-111: Composer merge-plugin keys: correct invalid option.
- ‘merge-false’ is not a valid key; replace it with ‘merge-dev’.
- ‘merge-replace’ and ‘replace’ are both valid per wikimedia/composer-merge-plugin v2.1 docs; no change needed.
Likely an incorrect or invalid review comment.
| public function resolvedMessage(array $responses, mixed $resolved): ?string { | ||
| return NULL; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
❓ Verification inconclusive
Public API change to resolvedMessage — ensure all overrides and call sites updated
Signature expansion is fine; confirm no handlers still implement the old single-arg method and no call sites pass one argument.
Add/upd phpdoc here and in overrides to document $resolved purpose and types for IDEs/static analysis.
🏁 Script executed:
#!/bin/bash
# Find handlers overriding old signature (no second param).
rg -nP --type=php 'function\s+resolvedMessage\s*\(\s*array\s+\$responses\s*(?!,)\s*\)' .vortex/installer/src/Prompts/Handlers
# Find call sites still passing a single argument.
rg -nP --type=php '->resolvedMessage\s*\(\s*[^,)]*\)' .vortex/installer/srcLength of output: 610
🏁 Script executed:
#!/bin/bash
# re-run override search
rg -nP --type=php -n 'function\s+resolvedMessage\s*\(\s*array\s+\$responses\s*(?!,)' .vortex/installer/src/Prompts/Handlers
# find call sites still passing a single argument
rg -nP --type=php -n '\b->resolvedMessage\s*\(\s*[^,)]*\)' .vortex/installer/srcLength of output: 208
Legacy single-arg resolvedMessage usage removed—all overrides and call sites now include both parameters. Optional: add or update phpdoc on resolvedMessage (and its overrides) to document the $resolved parameter for IDEs/static analysis.
🤖 Prompt for AI Agents
.vortex/installer/src/Prompts/Handlers/AbstractHandler.php around lines 137 to
139: the method signature was updated to accept the new $resolved parameter but
the phpdoc wasn't updated; add or update the docblock immediately above
resolvedMessage to document both parameters ($responses array and mixed
$resolved) and the ?string return type (including description of what $resolved
represents), and propagate the same phpdoc update to any overriding
implementations so IDEs and static analyzers recognize the new parameter.
| const INSTALL_PROFILE_CORE = 'install_profile_core'; | ||
|
|
||
| const DRUPAL_INSTALL_PROFILE = 'drupal_profile'; | ||
| const INSTALL_PROFILE_DRUPALCMS = 'install_profile_drupalcms'; | ||
|
|
||
| const LOAD_DATABASE_DEMO = 'load_demodb'; | ||
|
|
||
| const INSTALL_PROFILE_DRUPALCMS_PATH = '../recipes/drupal_cms_starter'; | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
❓ Verification inconclusive
Confirm usage of INSTALL_PROFILE_DRUPALCMS_PATH or remove it.
The constant isn’t referenced in this file. Verify it’s used elsewhere to avoid dead code.
🏁 Script executed:
#!/bin/bash
# Find references to the constant across the repo.
rg -nC2 '\bINSTALL_PROFILE_DRUPALCMS_PATH\b'Length of output: 46
Remove the unused constant INSTALL_PROFILE_DRUPALCMS_PATH. It isn’t referenced anywhere in the repo.
🤖 Prompt for AI Agents
In .vortex/installer/src/Prompts/Handlers/Starter.php around lines 12 to 19, the
constant INSTALL_PROFILE_DRUPALCMS_PATH is declared but unused; remove the
INSTALL_PROFILE_DRUPALCMS_PATH constant declaration from this file (delete the
line defining it) and run a quick repo-wide search to confirm it has no
references; adjust surrounding spacing/commas if needed to keep file formatting
consistent.
| if ($this->response == self::INSTALL_PROFILE_DRUPALCMS) { | ||
| $cj = JsonManipulator::fromFile($this->tmpDir . '/composer.json'); | ||
|
|
||
| $cj->addLink('require', 'drupal/cms', '^1.0', TRUE); | ||
| $cj->addLink('require', 'wikimedia/composer-merge-plugin', '^2.1', TRUE); | ||
| $cj->addLink('require', 'symfony/http-client', '^6.4 || ^7.0', TRUE); | ||
|
|
||
| $cj->addConfigSetting('allow-plugins.drupal/core-project-message', TRUE); | ||
| $cj->addConfigSetting('allow-plugins.wikimedia/composer-merge-plugin', TRUE); | ||
|
|
||
| $cj->addProperty('extra.merge-plugin.ignore-duplicates', FALSE); | ||
| $cj->addProperty('extra.merge-plugin.merge-false', TRUE); | ||
| $cj->addProperty('extra.merge-plugin.merge-extra', FALSE); | ||
| $cj->addProperty('extra.merge-plugin.merge-extra-deep', FALSE); | ||
| $cj->addProperty('extra.merge-plugin.merge-replace', TRUE); | ||
| $cj->addProperty('extra.merge-plugin.merge-scripts', FALSE); | ||
| $cj->addProperty('extra.merge-plugin.recurse', TRUE); | ||
| $cj->addProperty('extra.merge-plugin.replace', TRUE); | ||
| $cj->addProperty('extra.merge-plugin.require', ['vendor/drupal/cms/composer.json']); | ||
|
|
||
| $c = $cj->getContents(); | ||
| file_put_contents($this->tmpDir . '/composer.json', $c); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Fix loose comparison, null deref, missing installer-path, and Composer plugin allowances.
- Use strict comparison.
- Guard JsonManipulator::fromFile() returning NULL and check write result.
- Add allow-plugins for composer/installers to avoid Composer 2 blocks.
- Ensure recipes of type drupal-recipe install under web/recipes/{$name}.
- Replace invalid merge-false with merge-dev.
- if ($this->response == self::INSTALL_PROFILE_DRUPALCMS) {
- $cj = JsonManipulator::fromFile($this->tmpDir . '/composer.json');
+ if ($this->response === self::INSTALL_PROFILE_DRUPALCMS) {
+ $composerPath = $this->tmpDir . '/composer.json';
+ $cj = JsonManipulator::fromFile($composerPath);
+ if ($cj === NULL) {
+ throw new \RuntimeException(sprintf('composer.json not found or unreadable at %s', $composerPath));
+ }
@@
$cj->addLink('require', 'drupal/cms', '^1.0', TRUE);
$cj->addLink('require', 'wikimedia/composer-merge-plugin', '^2.1', TRUE);
$cj->addLink('require', 'symfony/http-client', '^6.4 || ^7.0', TRUE);
@@
$cj->addConfigSetting('allow-plugins.drupal/core-project-message', TRUE);
$cj->addConfigSetting('allow-plugins.wikimedia/composer-merge-plugin', TRUE);
+ $cj->addConfigSetting('allow-plugins.composer/installers', TRUE);
@@
$cj->addProperty('extra.merge-plugin.ignore-duplicates', FALSE);
- $cj->addProperty('extra.merge-plugin.merge-false', TRUE);
+ $cj->addProperty('extra.merge-plugin.merge-dev', TRUE);
$cj->addProperty('extra.merge-plugin.merge-extra', FALSE);
$cj->addProperty('extra.merge-plugin.merge-extra-deep', FALSE);
$cj->addProperty('extra.merge-plugin.merge-replace', TRUE);
$cj->addProperty('extra.merge-plugin.merge-scripts', FALSE);
$cj->addProperty('extra.merge-plugin.recurse', TRUE);
$cj->addProperty('extra.merge-plugin.replace', TRUE);
$cj->addProperty('extra.merge-plugin.require', ['vendor/drupal/cms/composer.json']);
+ $cj->addProperty('extra.installer-paths.web/recipes/{$name}', ['type:drupal-recipe']);
@@
- $c = $cj->getContents();
- file_put_contents($this->tmpDir . '/composer.json', $c);
+ $c = $cj->getContents();
+ if (file_put_contents($composerPath, $c) === FALSE) {
+ throw new \RuntimeException(sprintf('Failed to write composer.json to %s', $composerPath));
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if ($this->response == self::INSTALL_PROFILE_DRUPALCMS) { | |
| $cj = JsonManipulator::fromFile($this->tmpDir . '/composer.json'); | |
| $cj->addLink('require', 'drupal/cms', '^1.0', TRUE); | |
| $cj->addLink('require', 'wikimedia/composer-merge-plugin', '^2.1', TRUE); | |
| $cj->addLink('require', 'symfony/http-client', '^6.4 || ^7.0', TRUE); | |
| $cj->addConfigSetting('allow-plugins.drupal/core-project-message', TRUE); | |
| $cj->addConfigSetting('allow-plugins.wikimedia/composer-merge-plugin', TRUE); | |
| $cj->addProperty('extra.merge-plugin.ignore-duplicates', FALSE); | |
| $cj->addProperty('extra.merge-plugin.merge-false', TRUE); | |
| $cj->addProperty('extra.merge-plugin.merge-extra', FALSE); | |
| $cj->addProperty('extra.merge-plugin.merge-extra-deep', FALSE); | |
| $cj->addProperty('extra.merge-plugin.merge-replace', TRUE); | |
| $cj->addProperty('extra.merge-plugin.merge-scripts', FALSE); | |
| $cj->addProperty('extra.merge-plugin.recurse', TRUE); | |
| $cj->addProperty('extra.merge-plugin.replace', TRUE); | |
| $cj->addProperty('extra.merge-plugin.require', ['vendor/drupal/cms/composer.json']); | |
| $c = $cj->getContents(); | |
| file_put_contents($this->tmpDir . '/composer.json', $c); | |
| } | |
| if ($this->response === self::INSTALL_PROFILE_DRUPALCMS) { | |
| $composerPath = $this->tmpDir . '/composer.json'; | |
| $cj = JsonManipulator::fromFile($composerPath); | |
| if ($cj === NULL) { | |
| throw new \RuntimeException(sprintf('composer.json not found or unreadable at %s', $composerPath)); | |
| } | |
| $cj->addLink('require', 'drupal/cms', '^1.0', TRUE); | |
| $cj->addLink('require', 'wikimedia/composer-merge-plugin', '^2.1', TRUE); | |
| $cj->addLink('require', 'symfony/http-client', '^6.4 || ^7.0', TRUE); | |
| $cj->addConfigSetting('allow-plugins.drupal/core-project-message', TRUE); | |
| $cj->addConfigSetting('allow-plugins.wikimedia/composer-merge-plugin', TRUE); | |
| $cj->addConfigSetting('allow-plugins.composer/installers', TRUE); | |
| $cj->addProperty('extra.merge-plugin.ignore-duplicates', FALSE); | |
| $cj->addProperty('extra.merge-plugin.merge-dev', TRUE); | |
| $cj->addProperty('extra.merge-plugin.merge-extra', FALSE); | |
| $cj->addProperty('extra.merge-plugin.merge-extra-deep', FALSE); | |
| $cj->addProperty('extra.merge-plugin.merge-replace', TRUE); | |
| $cj->addProperty('extra.merge-plugin.merge-scripts', FALSE); | |
| $cj->addProperty('extra.merge-plugin.recurse', TRUE); | |
| $cj->addProperty('extra.merge-plugin.replace', TRUE); | |
| $cj->addProperty('extra.merge-plugin.require', ['vendor/drupal/cms/composer.json']); | |
| $cj->addProperty('extra.installer-paths.web/recipes/{$name}', ['type:drupal-recipe']); | |
| $c = $cj->getContents(); | |
| if (file_put_contents($composerPath, $c) === FALSE) { | |
| throw new \RuntimeException(sprintf('Failed to write composer.json to %s', $composerPath)); | |
| } | |
| } |
| /** | ||
| * Resolve a value via handler or prompt the user. | ||
| * | ||
| * This method is used to resolve a value via a handler's resolvedValue() | ||
| * method. If the value is not resolved, it will prompt the user using the | ||
| * provided prompt callable. | ||
| * | ||
| * @param string $handler_id | ||
| * The handler ID. | ||
| * @param array $r | ||
| * Current form responses for context-aware methods. | ||
| * @param callable $prompt | ||
| * The prompt callable to use if the value is not resolved. | ||
| * | ||
| * @return string | ||
| * The resolved value. | ||
| */ | ||
| protected function resolveOrPrompt(string $handler_id, array $r, callable $prompt): string { | ||
| $handler = $this->handlers[$handler_id]; | ||
| $resolved = $handler->resolvedValue($r); | ||
|
|
||
| if (is_string($resolved)) { | ||
| $message = $handler->resolvedMessage($r, $resolved); | ||
|
|
||
| if ($message) { | ||
| info($message); | ||
| } | ||
|
|
||
| return $resolved; | ||
| } | ||
|
|
||
| return (string) $prompt(); | ||
| } | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick (assertive)
Optional: guard handler existence in resolveOrPrompt.
Defensive check mirrors other parts of the class.
protected function resolveOrPrompt(string $handler_id, array $r, callable $prompt): string {
- $handler = $this->handlers[$handler_id];
+ if (!array_key_exists($handler_id, $this->handlers)) {
+ throw new \RuntimeException(sprintf('Handler for "%s" not found.', $handler_id));
+ }
+ $handler = $this->handlers[$handler_id];📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| /** | |
| * Resolve a value via handler or prompt the user. | |
| * | |
| * This method is used to resolve a value via a handler's resolvedValue() | |
| * method. If the value is not resolved, it will prompt the user using the | |
| * provided prompt callable. | |
| * | |
| * @param string $handler_id | |
| * The handler ID. | |
| * @param array $r | |
| * Current form responses for context-aware methods. | |
| * @param callable $prompt | |
| * The prompt callable to use if the value is not resolved. | |
| * | |
| * @return string | |
| * The resolved value. | |
| */ | |
| protected function resolveOrPrompt(string $handler_id, array $r, callable $prompt): string { | |
| $handler = $this->handlers[$handler_id]; | |
| $resolved = $handler->resolvedValue($r); | |
| if (is_string($resolved)) { | |
| $message = $handler->resolvedMessage($r, $resolved); | |
| if ($message) { | |
| info($message); | |
| } | |
| return $resolved; | |
| } | |
| return (string) $prompt(); | |
| } | |
| /** | |
| * Resolve a value via handler or prompt the user. | |
| * | |
| * This method is used to resolve a value via a handler's resolvedValue() | |
| * method. If the value is not resolved, it will prompt the user using the | |
| * provided prompt callable. | |
| * | |
| * @param string $handler_id | |
| * The handler ID. | |
| * @param array $r | |
| * Current form responses for context-aware methods. | |
| * @param callable $prompt | |
| * The prompt callable to use if the value is not resolved. | |
| * | |
| * @return string | |
| * The resolved value. | |
| */ | |
| protected function resolveOrPrompt(string $handler_id, array $r, callable $prompt): string { | |
| if (!array_key_exists($handler_id, $this->handlers)) { | |
| throw new \RuntimeException(sprintf('Handler for "%s" not found.', $handler_id)); | |
| } | |
| $handler = $this->handlers[$handler_id]; | |
| $resolved = $handler->resolvedValue($r); | |
| if (is_string($resolved)) { | |
| $message = $handler->resolvedMessage($r, $resolved); | |
| if ($message) { | |
| info($message); | |
| } | |
| return $resolved; | |
| } | |
| return (string) $prompt(); | |
| } |
🤖 Prompt for AI Agents
.vortex/installer/src/Prompts/PromptManager.php around lines 563 to 596:
resolveOrPrompt assumes $this->handlers[$handler_id] exists; add a defensive
guard like if (!isset($this->handlers[$handler_id])) { throw new
\InvalidArgumentException("Unknown handler: {$handler_id}"); } (or return a
sensible default) before using it, so the method mirrors other parts of the
class that validate handler existence and avoids undefined index errors.
| And I add the "page" content with the title "[TEST] Test page uniquestring" to the search index | ||
| And I add the "page" content with the title "[TEST] Test page otheruniquestring" to the search index | ||
| And I add the "page" content with the title "[TEST] Test page thirduniquestring" to the search index | ||
| And I run search indexing for 3 items |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick (assertive)
Avoid hardcoding the count; derive from created items.
Use a generic step if supported to reduce brittleness.
- And I run search indexing for 3 items
+ And I run search indexing for the created items📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| And I run search indexing for 3 items | |
| And I run search indexing for the created items |
🤖 Prompt for AI Agents
In tests/behat/features/search.feature around line 18, the step "And I run
search indexing for 3 items" hardcodes the count; replace it with a dynamic step
that derives the number from the created items (e.g., use the variable or
context that holds created items count) or switch to a generic step such as "And
I run search indexing for all items" if available, so the step uses the actual
number of created items instead of a fixed literal.
fff572d to
866f52c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (6)
composer.json (1)
152-156: Add “drupal-recipe” to installer-types or mapping won’t apply.Without this, oomphinc/composer-installers-extender won’t route type:drupal-recipe to recipes/{$name}.
"installer-types": [ "bower-asset", "npm-asset", - "drupal-library" + "drupal-library", + "drupal-recipe" ],.vortex/installer/src/Prompts/Handlers/HandlerInterface.php (4)
21-27: Grammar: “Label for of the handler.” → “Label for the handler.”- * Label for of the handler. + * Label for the handler.
52-57: Missing @param for placeholder($responses)/** * Optional placeholder. * + * @param array $responses + * Array of collected responses. * @return string|null * The placeholder text for the handler, or NULL if none. */
84-87: Doc mismatch: shouldRun returns bool, not “condition callback”/** * Check if the handler should run based on collected responses. * @@ - * @return bool - * The condition callback, or null if not conditional. + * @return bool + * TRUE to run this handler, FALSE to skip. */
182-185: Add @return for postInstall()/** * Actions to perform and messages to print after installation is complete. + * + * @return string|null + * A message to display post-install, or NULL for none. */.vortex/installer/src/Prompts/Handlers/Starter.php (1)
133-140: Differentiate build instructions for Drupal CMS; include DRUPAL_PROFILE. Also use strict compares.
This fulfills the PR objective to set DRUPAL_PROFILE when using the Drupal CMS recipe.- elseif ($this->response == self::INSTALL_PROFILE_CORE || $this->response == self::INSTALL_PROFILE_DRUPALCMS) { - $output .= 'Build project locally:' . PHP_EOL; - $output .= ' VORTEX_PROVISION_TYPE=profile ahoy build' . PHP_EOL; + elseif ($this->response === self::INSTALL_PROFILE_CORE || $this->response === self::INSTALL_PROFILE_DRUPALCMS) { + $output .= 'Build project locally:' . PHP_EOL; + if ($this->response === self::INSTALL_PROFILE_DRUPALCMS) { + $output .= ' DRUPAL_PROFILE=' . self::INSTALL_PROFILE_DRUPALCMS_PATH . ' VORTEX_PROVISION_TYPE=profile ahoy build' . PHP_EOL; + } + else { + $output .= ' VORTEX_PROVISION_TYPE=profile ahoy build' . PHP_EOL; + }
♻️ Duplicate comments (21)
.vortex/tests/test.workflow.sh (1)
81-86: Run docker-compose before Drupal CMS profile in default case (match case 3).Align ordering to avoid hidden deps and flakiness.
Apply:
*) phpunit "${TEST_DIR}"/phpunit bats "${TEST_DIR}"/bats/e2e/workflow.install.db.bats bats "${TEST_DIR}"/bats/e2e/workflow.install.profile.bats - bats "${TEST_DIR}"/bats/e2e/workflow.install.profile_drupalcms.bats - bats "${TEST_DIR}"/bats/e2e/workflow.docker-compose.bats + bats "${TEST_DIR}"/bats/e2e/workflow.docker-compose.bats + bats "${TEST_DIR}"/bats/e2e/workflow.install.profile_drupalcms.bats bats "${TEST_DIR}"/bats/e2e/workflow.install.provision.bats bats "${TEST_DIR}"/bats/e2e/workflow.storage.image.bats.vortex/tests/bats/_helper.bash (1)
534-538: Clarify intent: only guard markers are enforced, not all “#;” comments.Update the comment to remove ambiguity; keep generic “#;” check disabled.
- # Assert all special comments were removed. + # Assert VORTEX_DEV guard markers were removed (do not enforce removal of all "#;" comments). - # assert_dir_not_contains_string "${dir}" "#;" + # assert_dir_not_contains_string "${dir}" "#;" assert_dir_not_contains_string "${dir}" "#;<" assert_dir_not_contains_string "${dir}" "#;>".gitignore (1)
44-46: Keep an empty recipes/ directory in new repos.Add an exception and commit a placeholder to preserve the directory.
# Ignore all recipes by default. Custom recipes should be added explicitly. recipes/* +!recipes/.gitkeep.vortex/installer/src/Prompts/Handlers/HandlerInterface.php (2)
149-155: BC: resolvedMessage signature expanded — verify all implementers and call sitesEnsure every handler override accepts the new
$resolvedparam and all invocations pass it.Run:
#!/bin/bash # Overrides still using old single-arg signature rg -nP --type=php '(?s)class\s+\w+\s+implements\s+HandlerInterface.*?\bfunction\s+resolvedMessage\s*\(\s*array\s+\$responses\s*(?!,)\s*\)' .vortex/installer/src/Prompts/Handlers -C2 # Call sites passing only one arg rg -nP --type=php '\b->resolvedMessage\s*\(\s*[^,)\s]+\s*\)' .vortex/installer/src -n
143-145: Fix doc typos: PromptManager + promptingUpdate the doc to reference the correct manager and verb.
- * This is used by handlerManager to show an appropriate message (via - * info(), ok(), etc.) when using a resolved value instead of handlering + * This is used by PromptManager to show an appropriate message (via + * info(), ok(), etc.) when using a resolved value instead of prompting.vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
137-139: Add phpdoc for new $resolved param (even with {@inheritdoc})Helpful for IDEs/static analysers; mirror interface docs here.
- /** - * {@inheritdoc} - */ + /** + * {@inheritdoc} + * + * @param array $responses + * Collected responses. + * @param mixed $resolved + * Resolved value passed by PromptManager. + * + * @return string|null + */ public function resolvedMessage(array $responses, mixed $resolved): ?string {tests/behat/features/search.feature (2)
18-18: Don’t hardcode “3 items”; derive from created itemsPrevents fragility as data changes.
- And I run search indexing for 3 items + And I run search indexing for the created items
19-20: Avoid fixed sleeps; wait for index readinessReplace the arbitrary wait with a deterministic polling step.
- And I wait for 5 seconds - And I visit "/search" + And I wait for search indexing to complete + And I visit "/search"web/modules/custom/ys_search/config/install/search_api.index.content.yml (1)
61-69: Status field mapping looks good — plan update path + reindexAdd a post-update to import this config and trigger a full reindex on existing sites.
<?php // web/modules/custom/ys_search/ys_search.post_update.php /** * Add status field to search index and reindex content. */ function ys_search_post_update_add_status_field_and_reindex(&$sandbox = NULL): void { // Import updated config for the 'content' index. \Drupal::service('config.installer')->installOptionalConfig(['ys_search']); // Clear and reindex the 'content' index. $index = \Drupal::entityTypeManager()->getStorage('search_api_index')->load('content'); if ($index) { $index->clear(); \Drupal::service('search_api.index_task_manager')->addItems($index); } }Also document running: drush cim -y && drush sapi-c && drush sapi-i -y content.
</blockquote></details> <details> <summary>web/modules/custom/ys_search/config/install/views.view.search.yml (2)</summary><blockquote> `210-211`: **Switch to teaser view mode — verify bundle displays** Confirm all indexed bundles have a configured “teaser” display with expected fields; adjust if not. --- `165-202`: **Trim redundant expose/group blocks for non-exposed boolean filter** Keeps config lean; behaviour unchanged. ```diff status: id: status table: search_api_index_content field: status relationship: none group_type: group admin_label: '' plugin_id: search_api_boolean operator: '=' value: '1' group: 1 - exposed: false - expose: - operator_id: '' - label: '' - description: '' - use_operator: false - operator: '' - operator_limit_selection: false - operator_list: { } - identifier: '' - required: false - remember: false - multiple: false - remember_roles: - authenticated: authenticated - is_grouped: false - group_info: - label: '' - description: '' - identifier: '' - optional: true - widget: select - multiple: false - remember: false - default_group: All - default_group_multiple: { } - group_items: { } + exposed: false.vortex/tests/bats/e2e/workflow.install.profile_drupalcms.bats (3)
16-16: Good fix: use canonical Starter key for non-interactive path.install_profile_drupalcms is the correct option key.
39-40: Add teardown to clean environment leakage between tests.Unset env vars set in this test.
Apply:
assert_webpage_contains "/" "This is the home page of your new site." } +teardown() { + unset VORTEX_INSTALLER_PROMPT_STARTER VORTEX_INSTALLER_IS_DEMO_DB_DOWNLOAD_SKIP +}
24-27: Assert all composer mutations for this flow (missing symfony/http-client).Starter::process() also adds symfony/http-client; assert it to catch regressions.
Apply:
assert_file_contains composer.json "drupal/cms" assert_file_contains composer.json "wikimedia/composer-merge-plugin" assert_file_contains composer.json "vendor/drupal/cms/composer.json" + assert_file_contains composer.json "symfony/http-client".vortex/installer/tests/Functional/Handlers/StarterInstallTest.php (2)
14-15: Fix incorrect coverage target (should cover Starter).This test exercises the Starter handler. Point CoversClass to Starter.
-#[CoversClass(ProvisionType::class)] +#[CoversClass(Starter::class)]
27-34: Correct Drupal CMS assertions: expect composer mutations, not absence.Starter::process() adds drupal/cms, merge-plugin, http-client, and wires merge-plugin require. Assert presence and versions.
'starter, Drupal CMS profile' => [ static::cw(fn() => Env::put(PromptManager::makeEnvName(Starter::id()), Starter::INSTALL_PROFILE_DRUPALCMS)), - static::cw(fn(FunctionalTestCase $test) => $test->assertSutNotContains([ - 'drupal/cms', - 'wikimedia/composer-merge-plugin', - 'vendor/drupal/cms/composer.json', - ])), + static::cw(function (FunctionalTestCase $test) { + $composer = json_decode(file_get_contents(static::$sut . '/composer.json'), true); + $require = $composer['require'] ?? []; + $merge = $composer['extra']['merge-plugin'] ?? []; + + $test->assertArrayHasKey('drupal/cms', $require); + $test->assertEquals('^1.0', $require['drupal/cms']); + + $test->assertArrayHasKey('wikimedia/composer-merge-plugin', $require); + $test->assertEquals('^2.1', $require['wikimedia/composer-merge-plugin']); + + $test->assertArrayHasKey('symfony/http-client', $require); + $test->assertEquals('^6.4 || ^7.0', $require['symfony/http-client']); + + $test->assertContains('vendor/drupal/cms/composer.json', $merge['require'] ?? []); + }), ],.vortex/installer/src/Prompts/PromptManager.php (1)
563-596: Guard missing handler in resolveOrPrompt (defensive).Mirror checks used elsewhere to avoid undefined index errors.
protected function resolveOrPrompt(string $handler_id, array $r, callable $prompt): string { - $handler = $this->handlers[$handler_id]; + if (!array_key_exists($handler_id, $this->handlers)) { + throw new \RuntimeException(sprintf('Handler for "%s" not found.', $handler_id)); + } + $handler = $this->handlers[$handler_id];.vortex/installer/src/Prompts/Handlers/Profile.php (2)
145-146: Anchor DRUPAL_PROFILE replacement to the line (avoid accidental matches).- File::replaceContentInFile($t . '/.env', '/DRUPAL_PROFILE=.*/', 'DRUPAL_PROFILE=' . $v); + File::replaceContentInFile($t . '/.env', '/^DRUPAL_PROFILE=.*/m', 'DRUPAL_PROFILE=' . $v);
147-149: Make contrib-profile path detection OS-agnostic.Detect both '/' and '' to work on Windows and Unix.
- // Assume that profiles provided as a path are contrib profiles. - $is_contrib_profile = str_contains($v, DIRECTORY_SEPARATOR); + // Assume that profiles provided as a path are contrib profiles (detect '/' or '\'). + $is_contrib_profile = (strpbrk($v, '/\\') !== FALSE);Optionally add a unit test covering '../recipes/...' and '..\recipes\...'.
.vortex/installer/src/Prompts/Handlers/Starter.php (2)
31-39: Align labels with copy: use “recipe” and “Drupal CMS” consistently.
Update both description and option labels.- $label1 = Tui::bold('Drupal, installed from profile'); + $label1 = Tui::bold('Drupal, installed from recipe'); @@ - $label2 = Tui::bold('Drupal CMS, installed from profile'); + $label2 = Tui::bold('Drupal CMS, installed from recipe'); @@ - $label3 = Tui::bold('Drupal, loaded from the demo database'); + $label3 = Tui::bold('Drupal CMS, loaded from the demo database'); @@ - self::INSTALL_PROFILE_CORE => 'Drupal, installed from profile', - self::INSTALL_PROFILE_DRUPALCMS => 'Drupal CMS, installed from profile', - self::LOAD_DATABASE_DEMO => 'Drupal, loaded from the demo database', + self::INSTALL_PROFILE_CORE => 'Drupal, installed from recipe', + self::INSTALL_PROFILE_DRUPALCMS => 'Drupal CMS, installed from recipe', + self::LOAD_DATABASE_DEMO => 'Drupal CMS, loaded from the demo database',Also applies to: 69-72
93-115: Fix null-deref, strict compare, invalid merge flag, missing plugin allowance, and recipe installer-path.
Without these, installs can fatally fail or place recipes under vendor.- if ($this->response == self::INSTALL_PROFILE_DRUPALCMS) { - $cj = JsonManipulator::fromFile($this->tmpDir . '/composer.json'); + if ($this->response === self::INSTALL_PROFILE_DRUPALCMS) { + $composerPath = $this->tmpDir . '/composer.json'; + $cj = JsonManipulator::fromFile($composerPath); + if ($cj === NULL) { + throw new \RuntimeException(sprintf('composer.json not found or unreadable at %s', $composerPath)); + } @@ $cj->addLink('require', 'drupal/cms', '^1.0', TRUE); $cj->addLink('require', 'wikimedia/composer-merge-plugin', '^2.1', TRUE); $cj->addLink('require', 'symfony/http-client', '^6.4 || ^7.0', TRUE); @@ $cj->addConfigSetting('allow-plugins.drupal/core-project-message', TRUE); $cj->addConfigSetting('allow-plugins.wikimedia/composer-merge-plugin', TRUE); + $cj->addConfigSetting('allow-plugins.composer/installers', TRUE); @@ $cj->addProperty('extra.merge-plugin.ignore-duplicates', FALSE); - $cj->addProperty('extra.merge-plugin.merge-false', TRUE); + $cj->addProperty('extra.merge-plugin.merge-dev', TRUE); $cj->addProperty('extra.merge-plugin.merge-extra', FALSE); $cj->addProperty('extra.merge-plugin.merge-extra-deep', FALSE); $cj->addProperty('extra.merge-plugin.merge-replace', TRUE); $cj->addProperty('extra.merge-plugin.merge-scripts', FALSE); $cj->addProperty('extra.merge-plugin.recurse', TRUE); $cj->addProperty('extra.merge-plugin.replace', TRUE); $cj->addProperty('extra.merge-plugin.require', ['vendor/drupal/cms/composer.json']); + $cj->addProperty('extra.installer-paths.web/recipes/{$name}', ['type:drupal-recipe']); @@ - $c = $cj->getContents(); - file_put_contents($this->tmpDir . '/composer.json', $c); + $c = $cj->getContents(); + if (file_put_contents($composerPath, $c) === FALSE) { + throw new \RuntimeException(sprintf('Failed to write composer.json to %s', $composerPath)); + }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (23)
.vortex/installer/tests/Fixtures/install/_baseline/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/_baseline/composer.jsonis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/_baseline/phpmd.xmlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/_baseline/tests/behat/features/search.featureis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/_baseline/web/modules/custom/sw_search/config/install/search_api.index.content.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/_baseline/web/modules/custom/sw_search/config/install/views.view.search.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/hosting_acquia/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/hosting_acquia/composer.jsonis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/hosting_acquia/docroot/modules/custom/sw_search/config/install/search_api.index.content.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/hosting_acquia/docroot/modules/custom/sw_search/config/install/views.view.search.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/hosting_acquia/phpmd.xmlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/names/web/modules/custom/the_force_search/config/install/search_api.index.content.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/names/web/modules/custom/the_force_search/config/install/views.view.search.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/starter_demo_db/.ignorecontentis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/starter_drupal_cms_profile/.envis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/starter_drupal_cms_profile/composer.jsonis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/starter_drupal_profile/.envis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/theme_absent/phpmd.xmlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/tools_groups_no_be_tests/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/tools_groups_no_be_tests_circleci/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/tools_no_phpunit/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/tools_no_phpunit_circleci/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/tools_none/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**
📒 Files selected for processing (19)
.gitignore(2 hunks).vortex/installer/src/Prompts/Handlers/AbstractHandler.php(1 hunks).vortex/installer/src/Prompts/Handlers/HandlerInterface.php(1 hunks).vortex/installer/src/Prompts/Handlers/Internal.php(1 hunks).vortex/installer/src/Prompts/Handlers/Profile.php(2 hunks).vortex/installer/src/Prompts/Handlers/Starter.php(6 hunks).vortex/installer/src/Prompts/Handlers/Webroot.php(1 hunks).vortex/installer/src/Prompts/PromptManager.php(3 hunks).vortex/installer/tests/Functional/Handlers/StarterInstallTest.php(1 hunks).vortex/installer/tests/Unit/Handlers/AbstractPromptManagerTestCase.php(1 hunks).vortex/installer/tests/Unit/Handlers/StarterPromptManagerTest.php(2 hunks).vortex/tests/bats/_helper.bash(1 hunks).vortex/tests/bats/e2e/workflow.install.profile_drupalcms.bats(1 hunks).vortex/tests/test.workflow.sh(2 hunks)composer.json(1 hunks)phpmd.xml(1 hunks)tests/behat/features/search.feature(1 hunks)web/modules/custom/ys_search/config/install/search_api.index.content.yml(1 hunks)web/modules/custom/ys_search/config/install/views.view.search.yml(1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
composer.json
📄 CodeRabbit inference engine (CLAUDE.md)
When adding JavaScript or CSS libraries as Drupal libraries with Composer, define them as inline Composer packages in the 'repositories' section of composer.json
Files:
composer.json
tests/behat/**/*.feature
📄 CodeRabbit inference engine (CLAUDE.md)
tests/behat/**/*.feature: All Behat feature files must use the standard user story format: 'As a [user type]\nI want to [action]\nSo that [benefit]'
Use consistent user types in Behat feature files: 'site visitor', 'site administrator', and 'content editor'
Do not use commas or periods in user story statements within Behat feature files
Files:
tests/behat/features/search.feature
web/modules/custom/**
📄 CodeRabbit inference engine (CLAUDE.md)
Custom modules should be placed in 'web/modules/custom/'
Files:
web/modules/custom/ys_search/config/install/views.view.search.ymlweb/modules/custom/ys_search/config/install/search_api.index.content.yml
🧠 Learnings (1)
📚 Learning: 2025-08-08T12:02:24.652Z
Learnt from: AlexSkrypnyk
PR: drevops/vortex#1896
File: .vortex/tests/bats/unit/download-db-lagoon.bats:24-25
Timestamp: 2025-08-08T12:02:24.652Z
Learning: In .vortex/tests/bats/unit Bats tests using ../_helper.bash (run_steps), prefixing a STEPS entry with "- " denotes a negative assertion (the substring must NOT appear in output). Unprefixed entries are positive assertions. Example: "- Database dump refresh requested. Will create a new dump." asserts absence; "Database dump refresh requested. Will create a new dump." asserts presence.
Applied to files:
.vortex/tests/bats/_helper.bash.vortex/tests/bats/e2e/workflow.install.profile_drupalcms.bats.vortex/tests/test.workflow.sh
🧬 Code graph analysis (12)
.vortex/installer/tests/Functional/Handlers/StarterInstallTest.php (5)
.vortex/installer/src/Prompts/Handlers/ProvisionType.php (1)
ProvisionType(11-103).vortex/installer/src/Prompts/Handlers/Starter.php (1)
Starter(10-150).vortex/installer/src/Prompts/PromptManager.php (2)
PromptManager(58-597)makeEnvName(413-415).vortex/installer/src/Utils/Env.php (2)
Env(7-245)put(24-26).vortex/installer/tests/Functional/FunctionalTestCase.php (1)
assertSutNotContains(139-154)
.vortex/installer/tests/Unit/Handlers/AbstractPromptManagerTestCase.php (1)
.vortex/installer/src/Prompts/Handlers/Starter.php (1)
Starter(10-150)
.vortex/installer/src/Prompts/Handlers/HandlerInterface.php (3)
.vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
resolvedMessage(137-139).vortex/installer/src/Prompts/Handlers/Profile.php (1)
resolvedMessage(93-99).vortex/installer/src/Prompts/Handlers/Webroot.php (1)
resolvedMessage(115-121)
.vortex/installer/src/Prompts/Handlers/Internal.php (3)
.vortex/installer/src/Prompts/Handlers/Starter.php (1)
Starter(10-150).vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
id(52-62).vortex/installer/src/Prompts/Handlers/HandlerInterface.php (1)
id(19-19)
.vortex/tests/bats/e2e/workflow.install.profile_drupalcms.bats (2)
.vortex/tests/bats/_helper.workflow.bash (6)
prepare_sut(7-39)assert_ahoy_build(73-130)assert_gitignore(132-162)assert_ahoy_lint(413-425)assert_ahoy_test(527-544)assert_ahoy_fe(753-777).vortex/tests/bats/_helper.bash (1)
assert_webpage_contains(1022-1028)
.vortex/tests/test.workflow.sh (3)
.vortex/tests/test.common.sh (1)
bats(28-37).vortex/tests/test.deployment.sh (1)
bats(29-38).vortex/tests/test.postbuild.sh (1)
bats(20-29)
.vortex/installer/src/Prompts/Handlers/Webroot.php (3)
.vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
resolvedMessage(137-139).vortex/installer/src/Prompts/Handlers/HandlerInterface.php (1)
resolvedMessage(155-155).vortex/installer/src/Prompts/Handlers/Profile.php (1)
resolvedMessage(93-99)
.vortex/installer/src/Prompts/Handlers/AbstractHandler.php (3)
.vortex/installer/src/Prompts/Handlers/HandlerInterface.php (1)
resolvedMessage(155-155).vortex/installer/src/Prompts/Handlers/Profile.php (1)
resolvedMessage(93-99).vortex/installer/src/Prompts/Handlers/Webroot.php (1)
resolvedMessage(115-121)
.vortex/installer/src/Prompts/Handlers/Starter.php (2)
.vortex/installer/src/Utils/JsonManipulator.php (2)
JsonManipulator(10-76)fromFile(19-36).vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
AbstractHandler(10-233)
.vortex/installer/tests/Unit/Handlers/StarterPromptManagerTest.php (4)
.vortex/installer/src/Prompts/Handlers/Profile.php (1)
Profile(10-165).vortex/installer/src/Prompts/Handlers/Starter.php (1)
Starter(10-150).vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
id(52-62).vortex/installer/src/Prompts/Handlers/HandlerInterface.php (1)
id(19-19)
.vortex/installer/src/Prompts/Handlers/Profile.php (6)
.vortex/installer/src/Prompts/Handlers/AbstractHandler.php (4)
resolvedValue(130-132)id(52-62)resolvedMessage(137-139)getResponseAsString(191-197).vortex/installer/src/Prompts/Handlers/HandlerInterface.php (3)
resolvedValue(138-138)id(19-19)resolvedMessage(155-155).vortex/installer/src/Prompts/Handlers/Webroot.php (4)
resolvedValue(98-110)discover(65-79)resolvedMessage(115-121)process(126-146).vortex/installer/src/Prompts/Handlers/Starter.php (1)
Starter(10-150).vortex/installer/src/Prompts/Handlers/ProfileCustom.php (1)
ProfileCustom(9-86).vortex/installer/src/Utils/File.php (2)
File(10-102)replaceContentAsync(59-83)
.vortex/installer/src/Prompts/PromptManager.php (4)
.vortex/installer/src/Prompts/Handlers/Profile.php (3)
Profile(10-165)resolvedValue(76-88)resolvedMessage(93-99).vortex/installer/src/Prompts/Handlers/AbstractHandler.php (3)
id(52-62)resolvedValue(130-132)resolvedMessage(137-139).vortex/installer/src/Prompts/Handlers/Webroot.php (3)
Webroot(12-148)resolvedValue(98-110)resolvedMessage(115-121).vortex/installer/src/Utils/Tui.php (1)
info(42-44)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (13)
- GitHub Check: build (1)
- GitHub Check: build (0)
- GitHub Check: vortex-test-deployment (1)
- GitHub Check: vortex-test-deployment (0)
- GitHub Check: vortex-test-workflow (3)
- GitHub Check: vortex-test-workflow (2)
- GitHub Check: vortex-test-workflow (1)
- GitHub Check: vortex-test-workflow (0)
- GitHub Check: vortex-test-common
- GitHub Check: vortex-test-installer (8.2)
- GitHub Check: vortex-test-installer (8.4)
- GitHub Check: vortex-test-installer (8.3)
- GitHub Check: vortex-test-docs
🔇 Additional comments (16)
phpmd.xml (1)
17-18: Exclude recipes from PHPMD — LGTM.Matches new installer-paths and avoids linting vendor-like recipe code.
composer.json (2)
133-139: Confirm intended recipes target path (root vs web/recipes).Issue text says web/recipes/{$name}, code uses recipes/{$name}. Tests reference ../recipes/… from web/, which aligns with root-level recipes. Please confirm this is the desired contract.
73-91: If “wikimedia/composer-merge-plugin” is injected during install, remember allow-plugins.Composer will require allow-plugins entry for the merge plugin at runtime. Verify installer updates config when adding the plugin.
.gitignore (1)
34-34: Comment tweak — OK as-is.No functional change; wording is fine.
.vortex/installer/tests/Unit/Handlers/AbstractPromptManagerTestCase.php (1)
124-124: Defaults updated to new Starter key — consistent with handler.Matches Starter::default() and downstream gating. No further action.
.vortex/installer/src/Prompts/Handlers/Webroot.php (1)
115-118: Signature migration to resolvedMessage(responses, resolved) looks correct.Message uses the centrally resolved value; aligns with HandlerInterface/AbstractHandler changes.
.vortex/installer/tests/Unit/Handlers/StarterPromptManagerTest.php (1)
7-7: No stale constants; options order and default selection verified..vortex/installer/tests/Functional/Handlers/StarterInstallTest.php (1)
7-7: Drop unused ProvisionType import after fixing CoversClass.
[ suggest_nitpick ]-use DrevOps\VortexInstaller\Prompts\Handlers\ProvisionType;.vortex/installer/src/Prompts/PromptManager.php (2)
128-130: Good reuse of resolveOrPrompt for Profile.
153-154: Good reuse of resolveOrPrompt for Webroot..vortex/installer/src/Prompts/Handlers/Profile.php (2)
76-88: LGTM: resolves DrupalCMS profile to recipe path via constant.
90-99: LGTM: concise resolved message..vortex/installer/src/Prompts/Handlers/Starter.php (4)
7-7: LGTM: JsonManipulator import is correct.
12-17: LGTM: New constants read clearly and align with flows.
79-79: Default choice change acknowledged.
Defaulting to demo DB is fine if it matches e2e expectations.
98-98: LGTM: Symfony constraint widened to ^6.4 || ^7.0.
Matches modern stacks.
| if ($responses[Starter::id()] !== Starter::LOAD_DATABASE_DEMO) { | ||
| $is_demo = FALSE; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Harden access to Starter response to avoid undefined index.
In some non-interactive or partial-resolution paths, Starter::id() may be absent; use null coalescing.
Apply:
- if ($responses[Starter::id()] !== Starter::LOAD_DATABASE_DEMO) {
+ if (($responses[Starter::id()] ?? null) !== Starter::LOAD_DATABASE_DEMO) {
$is_demo = FALSE;
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if ($responses[Starter::id()] !== Starter::LOAD_DATABASE_DEMO) { | |
| $is_demo = FALSE; | |
| } | |
| if (($responses[Starter::id()] ?? null) !== Starter::LOAD_DATABASE_DEMO) { | |
| $is_demo = FALSE; | |
| } |
🤖 Prompt for AI Agents
.vortex/installer/src/Prompts/Handlers/Internal.php around lines 127 to 129: the
code directly indexes $responses[Starter::id()] which can be undefined; change
the check to use a null-coalescing lookup (e.g. $responses[Starter::id()] ??
null) or assign a local variable with ($responses[Starter::id()] ?? null) and
compare that to Starter::LOAD_DATABASE_DEMO so the undefined index is avoided
and $is_demo is set correctly.
|
|
||
| const LOAD_DATABASE_DEMO = 'load_demodb'; | ||
|
|
||
| const INSTALL_PROFILE_DRUPALCMS_PATH = '../recipes/drupal_cms_starter'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
❓ Verification inconclusive
Verify this constant is actually used; otherwise remove or use it in postInstall.
If unused, delete; if used, prefer referencing it when constructing DRUPAL_PROFILE.
Run to confirm:
🏁 Script executed:
#!/bin/bash
rg -nC2 '\bINSTALL_PROFILE_DRUPALCMS_PATH\b'Length of output: 46
Remove unused INSTALL_PROFILE_DRUPALCMS_PATH constant
This constant is defined in .vortex/installer/src/Prompts/Handlers/Starter.php but never referenced—delete it.
🤖 Prompt for AI Agents
In .vortex/installer/src/Prompts/Handlers/Starter.php around line 18, the
constant INSTALL_PROFILE_DRUPALCMS_PATH is declared but never used; remove the
unused constant declaration from the file to eliminate dead code and unused
symbol warnings, and run tests/lint to confirm no references remain.
| $output = ''; | ||
|
|
||
| if ($this->response == self::DRUPAL_LOAD_DATABASE_DEMO) { | ||
| if ($this->response == self::LOAD_DATABASE_DEMO) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick (assertive)
Use strict comparison.
- if ($this->response == self::LOAD_DATABASE_DEMO) {
+ if ($this->response === self::LOAD_DATABASE_DEMO) {📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if ($this->response == self::LOAD_DATABASE_DEMO) { | |
| if ($this->response === self::LOAD_DATABASE_DEMO) { |
🤖 Prompt for AI Agents
.vortex/installer/src/Prompts/Handlers/Starter.php around line 128: the
condition uses loose equality (==) when comparing $this->response to the
constant self::LOAD_DATABASE_DEMO; change it to a strict comparison (===) so the
types and values must match exactly (or cast $this->response to the expected
type before comparing) to prevent unintended truthy/loose-equality matches.
| namespace DrevOps\VortexInstaller\Tests\Functional\Handlers; | ||
|
|
||
| use DrevOps\VortexInstaller\Prompts\Handlers\ProvisionType; | ||
| use DrevOps\VortexInstaller\Prompts\Handlers\Starter; | ||
| use DrevOps\VortexInstaller\Prompts\PromptManager; | ||
| use DrevOps\VortexInstaller\Tests\Functional\FunctionalTestCase; | ||
| use DrevOps\VortexInstaller\Utils\Env; | ||
| use PHPUnit\Framework\Attributes\CoversClass; | ||
|
|
||
| #[CoversClass(ProvisionType::class)] | ||
| class StarterInstallTest extends AbstractInstallTestCase { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Import the correct base test class to avoid namespacing error.
AbstractInstallTestCase is in the parent namespace; without an import this will fatal.
namespace DrevOps\VortexInstaller\Tests\Functional\Handlers;
+use DrevOps\VortexInstaller\Tests\Functional\AbstractInstallTestCase;
use DrevOps\VortexInstaller\Prompts\Handlers\ProvisionType;
use DrevOps\VortexInstaller\Prompts\Handlers\Starter;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| namespace DrevOps\VortexInstaller\Tests\Functional\Handlers; | |
| use DrevOps\VortexInstaller\Prompts\Handlers\ProvisionType; | |
| use DrevOps\VortexInstaller\Prompts\Handlers\Starter; | |
| use DrevOps\VortexInstaller\Prompts\PromptManager; | |
| use DrevOps\VortexInstaller\Tests\Functional\FunctionalTestCase; | |
| use DrevOps\VortexInstaller\Utils\Env; | |
| use PHPUnit\Framework\Attributes\CoversClass; | |
| #[CoversClass(ProvisionType::class)] | |
| class StarterInstallTest extends AbstractInstallTestCase { | |
| namespace DrevOps\VortexInstaller\Tests\Functional\Handlers; | |
| use DrevOps\VortexInstaller\Tests\Functional\AbstractInstallTestCase; | |
| use DrevOps\VortexInstaller\Prompts\Handlers\ProvisionType; | |
| use DrevOps\VortexInstaller\Prompts\Handlers\Starter; | |
| use DrevOps\VortexInstaller\Prompts\PromptManager; | |
| use DrevOps\VortexInstaller\Tests\Functional\FunctionalTestCase; | |
| use DrevOps\VortexInstaller\Utils\Env; | |
| use PHPUnit\Framework\Attributes\CoversClass; | |
| #[CoversClass(ProvisionType::class)] | |
| class StarterInstallTest extends AbstractInstallTestCase { | |
| // … | |
| } |
🤖 Prompt for AI Agents
.vortex/installer/tests/Functional/Handlers/StarterInstallTest.php lines 5-15:
the class extends AbstractInstallTestCase but the file doesn't import that base
class from the parent namespace, causing a fatal namespacing error; add the
correct use statement (use
DrevOps\VortexInstaller\Tests\Functional\AbstractInstallTestCase;) near the
other use lines so the class can resolve the parent test class.
| And I add the "page" content with the title "[TEST] Test page uniquestring" to the search index | ||
| And I add the "page" content with the title "[TEST] Test page otheruniquestring" to the search index | ||
| And I add the "page" content with the title "[TEST] Test page thirduniquestring" to the search index |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick (assertive)
Reduce duplication: use a single step to index created content (if available)
Keeps the scenario concise and less brittle.
- And I add the "page" content with the title "[TEST] Test page uniquestring" to the search index
- And I add the "page" content with the title "[TEST] Test page otheruniquestring" to the search index
- And I add the "page" content with the title "[TEST] Test page thirduniquestring" to the search index
+ And I add the created items to the search index📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| And I add the "page" content with the title "[TEST] Test page uniquestring" to the search index | |
| And I add the "page" content with the title "[TEST] Test page otheruniquestring" to the search index | |
| And I add the "page" content with the title "[TEST] Test page thirduniquestring" to the search index | |
| And I add the created items to the search index |
🤖 Prompt for AI Agents
In tests/behat/features/search.feature around lines 15 to 17, there are three
nearly identical steps that add separate pages to the search index; replace
these with a single consolidated step that indexes multiple pages in one call to
reduce duplication. Change the three lines to one step that accepts multiple
titles (for example "And I add the following pages to the search index:"
followed by a data table of titles) or convert the scenario into a Scenario
Outline with an Examples table so the step definition can loop over each title
and call the existing index step once for each item; update or reuse the step
definition to iterate the table rows and call the indexing logic so behavior
stays the same but the feature is concise.
866f52c to
5be8d87
Compare
5be8d87 to
a3328d6
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
♻️ Duplicate comments (22)
tests/behat/features/search.feature (3)
15-17: Deduplicate indexing steps.Replace the three identical “add … to the search index” steps with a single bulk step to reduce brittleness.
Apply:
- And I add the "page" content with the title "[TEST] Test page uniquestring" to the search index - And I add the "page" content with the title "[TEST] Test page otheruniquestring" to the search index - And I add the "page" content with the title "[TEST] Test page thirduniquestring" to the search index + And I add the created items to the search index
18-18: Avoid hardcoded count in indexing.Derive the number from created items (or use an “all/created items” step) to prevent drift.
Apply:
- And I run search indexing for 3 items + And I run search indexing for the created items
19-21: Remove fixed sleep; wait deterministically for index readiness.Use a polling/wait step instead of “wait 5 seconds” to reduce flakiness.
Apply:
- And I wait for 5 seconds - And I visit "/search" + And I wait for search indexing to complete + And I visit "/search"Run to confirm supporting steps exist:
#!/bin/bash rg -nC2 -P 'I wait for search indexing to complete|I run search indexing for the created items|I add the created items to the search index' -- tests behatweb/modules/custom/ys_search/config/install/search_api.index.content.yml (1)
61-69: Adding boolean status field — good; ensure deploy path + reindex.Ship a config update/post-update to import this change and trigger a full reindex to avoid stale results on existing sites.
Suggestion (deploy ops):
- drush cim -y
- drush sapi-c
- drush sapi-i -y content
web/modules/custom/ys_search/config/install/views.view.search.yml (1)
165-202: Trim redundant expose/group blocks for a non-exposed filter.Since exposed: false, drop expose and group_info to reduce noise.
Apply:
status: id: status table: search_api_index_content field: status relationship: none group_type: group admin_label: '' plugin_id: search_api_boolean operator: '=' value: '1' group: 1 - exposed: false - expose: - operator_id: '' - label: '' - description: '' - use_operator: false - operator: '' - operator_limit_selection: false - operator_list: { } - identifier: '' - required: false - remember: false - multiple: false - remember_roles: - authenticated: authenticated - is_grouped: false - group_info: - label: '' - description: '' - identifier: '' - optional: true - widget: select - multiple: false - remember: false - default_group: All - default_group_multiple: { } - group_items: { } + exposed: false.vortex/tests/bats/_helper.bash (1)
534-538: Align the comment with the actual assertions and drop the dead check.We only assert removal of VORTEX_DEV guard markers, not all “#;” comments. Update the wording and remove the commented-out assertion to avoid confusion.
- # Assert all special comments were removed. - # assert_dir_not_contains_string "${dir}" "#;" + # Assert VORTEX_DEV guard markers were removed (do not assert removal of all '#;' comments). assert_dir_not_contains_string "${dir}" "#;<" assert_dir_not_contains_string "${dir}" "#;>"composer.json (1)
133-136: Add "drupal-recipe" to extra.installer-types in composer.jsonMapping recipes/{$name} → type:drupal-recipe will not be applied until "drupal-recipe" is declared.
"installer-types": [ "bower-asset", "npm-asset", - "drupal-library" + "drupal-library", + "drupal-recipe" ],Confirm recipes are located at project root (recipes/{$name}); tests may expect ../recipes from web/ — verify.
.gitignore (1)
44-46: Keep the recipes directory while ignoring its contents.Add an exception for a keep file so the empty directory can be committed when needed.
# Ignore all recipes by default. Custom recipes should be added explicitly. recipes/* +!recipes/.gitkeep.vortex/installer/src/Prompts/Handlers/Internal.php (1)
127-131: Harden Starter lookup to avoid undefined index notices.Use a null-coalescing read when $responses may not include Starter::id().
- if ($responses[Starter::id()] !== Starter::LOAD_DATABASE_DEMO) { + if (($responses[Starter::id()] ?? null) !== Starter::LOAD_DATABASE_DEMO) { $is_demo = FALSE; }.vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
137-139: Add phpdoc for the new resolvedMessage signature.Document $resolved and return type for IDEs/static analysis.
- public function resolvedMessage(array $responses, mixed $resolved): ?string { + /** + * Message shown when a value was resolved without prompting. + * + * @param array $responses + * All collected responses. + * @param mixed $resolved + * The resolved value for this handler. + * + * @return string|null + * Message to display, or NULL for none. + */ + public function resolvedMessage(array $responses, mixed $resolved): ?string { return NULL; }.vortex/tests/test.workflow.sh (1)
83-89: Swap default-case order to match case 4 and avoid hidden deps.Run docker-compose before the Drupal CMS profile test.
bats "${TEST_DIR}"/bats/e2e/workflow.install.profile.bats - bats "${TEST_DIR}"/bats/e2e/workflow.install.profile_drupalcms.bats - bats "${TEST_DIR}"/bats/e2e/workflow.docker-compose.bats + bats "${TEST_DIR}"/bats/e2e/workflow.docker-compose.bats + bats "${TEST_DIR}"/bats/e2e/workflow.install.profile_drupalcms.bats.vortex/installer/src/Prompts/Handlers/HandlerInterface.php (1)
141-146: Fix doc typos (“handlerManager” → “PromptManager”; “handlering” → “prompting”).
Small doc nits right above the changed block.Apply:
- * This is used by handlerManager to show an appropriate message (via - * info(), ok(), etc.) when using a resolved value instead of handlering + * This is used by PromptManager to show an appropriate message (via + * info(), ok(), etc.) when using a resolved value instead of prompting.vortex/installer/tests/Functional/Handlers/StarterInstallTest.php (2)
5-15: Missing import for the base class will fatal.
Add the parent test class import.use DrevOps\VortexInstaller\Prompts\Handlers\Starter; use DrevOps\VortexInstaller\Prompts\PromptManager; use DrevOps\VortexInstaller\Tests\Functional\FunctionalTestCase; +use DrevOps\VortexInstaller\Tests\Functional\AbstractInstallTestCase; use DrevOps\VortexInstaller\Utils\Env;
26-33: Wrong assertion: these packages should be present, not absent. Also assert all composer mutations.
Flip to positive checks and validate merge-plugin config to catch regressions (e.g., key typos).- 'starter, Drupal CMS profile' => [ - static::cw(fn() => Env::put(PromptManager::makeEnvName(Starter::id()), Starter::INSTALL_PROFILE_DRUPALCMS)), - static::cw(fn(FunctionalTestCase $test) => $test->assertSutNotContains([ - 'drupal/cms', - 'wikimedia/composer-merge-plugin', - 'vendor/drupal/cms/composer.json', - ])), - ], + 'starter, Drupal CMS profile' => [ + static::cw(fn() => Env::put(PromptManager::makeEnvName(Starter::id()), Starter::INSTALL_PROFILE_DRUPALCMS)), + static::cw(function (FunctionalTestCase $test): void { + $composer = json_decode(file_get_contents(static::$sut . '/composer.json'), true); + $require = $composer['require'] ?? []; + $merge = $composer['extra']['merge-plugin'] ?? []; + + $test->assertArrayHasKey('drupal/cms', $require); + $test->assertArrayHasKey('wikimedia/composer-merge-plugin', $require); + $test->assertArrayHasKey('symfony/http-client', $require); + $test->assertContains('vendor/drupal/cms/composer.json', $merge['require'] ?? []); + + // Ensure correct merge-plugin option name. + $test->assertArrayHasKey('merge-dev', $merge); + $test->assertArrayNotHasKey('merge-false', $merge); + }), + ],.vortex/tests/bats/e2e/workflow.install.profile_drupalcms.bats (2)
24-27: Also assert symfony/http-client to cover all composer edits.
Catches partial writes/regressions.assert_file_contains composer.json "drupal/cms" assert_file_contains composer.json "wikimedia/composer-merge-plugin" assert_file_contains composer.json "vendor/drupal/cms/composer.json" + assert_file_contains composer.json "symfony/http-client"
39-40: Add teardown to prevent env leakage across tests.
Keeps suite isolated.assert_webpage_contains "/" "This is the home page of your new site." } + +teardown() { + unset VORTEX_INSTALLER_PROMPT_STARTER VORTEX_INSTALLER_IS_DEMO_DB_DOWNLOAD_SKIP +}.vortex/installer/src/Prompts/PromptManager.php (1)
563-596: Defensively guard handler existence in resolveOrPrompt.
Prevents undefined-index fatals if a handler is missing.protected function resolveOrPrompt(string $handler_id, array $r, callable $prompt): string { - $handler = $this->handlers[$handler_id]; + if (!array_key_exists($handler_id, $this->handlers)) { + throw new \RuntimeException(sprintf('Handler for "%s" not found.', $handler_id)); + } + $handler = $this->handlers[$handler_id];.vortex/installer/src/Prompts/Handlers/Profile.php (2)
145-146: Anchor DRUPAL_PROFILE replacement to the line (multiline).
Prevents accidental replacements elsewhere in the file.- File::replaceContentInFile($t . '/.env', '/DRUPAL_PROFILE=.*/', 'DRUPAL_PROFILE=' . $v); + File::replaceContentInFile($t . '/.env', '/^DRUPAL_PROFILE=.*/m', 'DRUPAL_PROFILE=' . $v);
147-149: Make contrib-path detection OS-agnostic.
Detect both '/' and '' to work on Windows paths too.- $is_contrib_profile = str_contains($v, DIRECTORY_SEPARATOR); + // Detect both Unix and Windows separators in provided path. + $is_contrib_profile = (strpbrk($v, '/\\') !== FALSE);.vortex/installer/src/Prompts/Handlers/Starter.php (3)
128-140: Use strict comparisons in postInstall.
Prevents loose-equality surprises and reads cleaner.- if ($this->response == self::LOAD_DATABASE_DEMO) { + if ($this->response === self::LOAD_DATABASE_DEMO) { @@ - elseif ($this->response == self::INSTALL_PROFILE_CORE || $this->response == self::INSTALL_PROFILE_DRUPALCMS) { + elseif (in_array($this->response, [self::INSTALL_PROFILE_CORE, self::INSTALL_PROFILE_DRUPALCMS], TRUE)) {Also applies to: 133-140
34-39: Align wording: use “recipe” for Drupal CMS.
Match the description and PR objective terminology.- $label2 = Tui::bold('Drupal CMS, installed from profile'); + $label2 = Tui::bold('Drupal CMS, installed from recipe'); @@ - self::INSTALL_PROFILE_DRUPALCMS => 'Drupal CMS, installed from profile', + self::INSTALL_PROFILE_DRUPALCMS => 'Drupal CMS, installed from recipe',Also applies to: 69-72
93-115: Fix Composer mutations: strict compare, null-guard, installer path, plugin allowances, and merge option.
Without these, CMS install can fail or write invalid config.- if ($this->response == self::INSTALL_PROFILE_DRUPALCMS) { - $cj = JsonManipulator::fromFile($this->tmpDir . '/composer.json'); + if ($this->response === self::INSTALL_PROFILE_DRUPALCMS) { + $composerPath = $this->tmpDir . '/composer.json'; + $cj = JsonManipulator::fromFile($composerPath); + if ($cj === NULL) { + throw new \RuntimeException(sprintf('composer.json not found or unreadable at %s', $composerPath)); + } $cj->addLink('require', 'drupal/cms', '^1.0', TRUE); $cj->addLink('require', 'wikimedia/composer-merge-plugin', '^2.1', TRUE); $cj->addLink('require', 'symfony/http-client', '^6.4 || ^7.0', TRUE); $cj->addConfigSetting('allow-plugins.drupal/core-project-message', TRUE); $cj->addConfigSetting('allow-plugins.wikimedia/composer-merge-plugin', TRUE); + $cj->addConfigSetting('allow-plugins.composer/installers', TRUE); $cj->addProperty('extra.merge-plugin.ignore-duplicates', FALSE); - $cj->addProperty('extra.merge-plugin.merge-false', TRUE); + $cj->addProperty('extra.merge-plugin.merge-dev', TRUE); $cj->addProperty('extra.merge-plugin.merge-extra', FALSE); $cj->addProperty('extra.merge-plugin.merge-extra-deep', FALSE); $cj->addProperty('extra.merge-plugin.merge-replace', TRUE); $cj->addProperty('extra.merge-plugin.merge-scripts', FALSE); $cj->addProperty('extra.merge-plugin.recurse', TRUE); $cj->addProperty('extra.merge-plugin.replace', TRUE); $cj->addProperty('extra.merge-plugin.require', ['vendor/drupal/cms/composer.json']); + $cj->addProperty('extra.installer-paths.web/recipes/{$name}', ['type:drupal-recipe']); - $c = $cj->getContents(); - file_put_contents($this->tmpDir . '/composer.json', $c); + $c = $cj->getContents(); + if (file_put_contents($composerPath, $c) === FALSE) { + throw new \RuntimeException(sprintf('Failed to write composer.json to %s', $composerPath)); + } }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (23)
.vortex/installer/tests/Fixtures/install/_baseline/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/_baseline/composer.jsonis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/_baseline/phpmd.xmlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/_baseline/tests/behat/features/search.featureis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/_baseline/web/modules/custom/sw_search/config/install/search_api.index.content.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/_baseline/web/modules/custom/sw_search/config/install/views.view.search.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/hosting_acquia/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/hosting_acquia/composer.jsonis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/hosting_acquia/docroot/modules/custom/sw_search/config/install/search_api.index.content.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/hosting_acquia/docroot/modules/custom/sw_search/config/install/views.view.search.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/hosting_acquia/phpmd.xmlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/names/web/modules/custom/the_force_search/config/install/search_api.index.content.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/names/web/modules/custom/the_force_search/config/install/views.view.search.ymlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/starter_demo_db/.ignorecontentis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/starter_drupal_cms_profile/.envis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/starter_drupal_cms_profile/composer.jsonis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/starter_drupal_profile/.envis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/theme_absent/phpmd.xmlis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/tools_groups_no_be_tests/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/tools_groups_no_be_tests_circleci/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/tools_no_phpunit/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/tools_no_phpunit_circleci/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**.vortex/installer/tests/Fixtures/install/tools_none/.gitignoreis excluded by!.vortex/installer/tests/Fixtures/**
📒 Files selected for processing (21)
.github/workflows/build-test-deploy.yml(1 hunks).github/workflows/vortex-test-common.yml(2 hunks).gitignore(2 hunks).vortex/installer/src/Prompts/Handlers/AbstractHandler.php(1 hunks).vortex/installer/src/Prompts/Handlers/HandlerInterface.php(1 hunks).vortex/installer/src/Prompts/Handlers/Internal.php(1 hunks).vortex/installer/src/Prompts/Handlers/Profile.php(2 hunks).vortex/installer/src/Prompts/Handlers/Starter.php(6 hunks).vortex/installer/src/Prompts/Handlers/Webroot.php(1 hunks).vortex/installer/src/Prompts/PromptManager.php(3 hunks).vortex/installer/tests/Functional/Handlers/StarterInstallTest.php(1 hunks).vortex/installer/tests/Unit/Handlers/AbstractPromptManagerTestCase.php(1 hunks).vortex/installer/tests/Unit/Handlers/StarterPromptManagerTest.php(2 hunks).vortex/tests/bats/_helper.bash(1 hunks).vortex/tests/bats/e2e/workflow.install.profile_drupalcms.bats(1 hunks).vortex/tests/test.workflow.sh(1 hunks)composer.json(1 hunks)phpmd.xml(1 hunks)tests/behat/features/search.feature(1 hunks)web/modules/custom/ys_search/config/install/search_api.index.content.yml(1 hunks)web/modules/custom/ys_search/config/install/views.view.search.yml(1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
composer.json
📄 CodeRabbit inference engine (CLAUDE.md)
When adding JavaScript or CSS libraries as Drupal libraries with Composer, define them as inline Composer packages in the 'repositories' section of composer.json
Files:
composer.json
web/modules/custom/**
📄 CodeRabbit inference engine (CLAUDE.md)
Custom modules should be placed in 'web/modules/custom/'
Files:
web/modules/custom/ys_search/config/install/views.view.search.ymlweb/modules/custom/ys_search/config/install/search_api.index.content.yml
tests/behat/**/*.feature
📄 CodeRabbit inference engine (CLAUDE.md)
tests/behat/**/*.feature: All Behat feature files must use the standard user story format: 'As a [user type]\nI want to [action]\nSo that [benefit]'
Use consistent user types in Behat feature files: 'site visitor', 'site administrator', and 'content editor'
Do not use commas or periods in user story statements within Behat feature files
Files:
tests/behat/features/search.feature
🧠 Learnings (1)
📚 Learning: 2025-08-08T12:02:24.652Z
Learnt from: AlexSkrypnyk
PR: drevops/vortex#1896
File: .vortex/tests/bats/unit/download-db-lagoon.bats:24-25
Timestamp: 2025-08-08T12:02:24.652Z
Learning: In .vortex/tests/bats/unit Bats tests using ../_helper.bash (run_steps), prefixing a STEPS entry with "- " denotes a negative assertion (the substring must NOT appear in output). Unprefixed entries are positive assertions. Example: "- Database dump refresh requested. Will create a new dump." asserts absence; "Database dump refresh requested. Will create a new dump." asserts presence.
Applied to files:
.vortex/tests/bats/_helper.bash.vortex/tests/test.workflow.sh.vortex/tests/bats/e2e/workflow.install.profile_drupalcms.bats
🧬 Code graph analysis (12)
.vortex/installer/src/Prompts/Handlers/HandlerInterface.php (3)
.vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
resolvedMessage(137-139).vortex/installer/src/Prompts/Handlers/Profile.php (1)
resolvedMessage(93-99).vortex/installer/src/Prompts/Handlers/Webroot.php (1)
resolvedMessage(115-121)
.vortex/installer/src/Prompts/Handlers/Webroot.php (3)
.vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
resolvedMessage(137-139).vortex/installer/src/Prompts/Handlers/HandlerInterface.php (1)
resolvedMessage(155-155).vortex/installer/src/Prompts/Handlers/Profile.php (1)
resolvedMessage(93-99)
.vortex/installer/src/Prompts/Handlers/AbstractHandler.php (3)
.vortex/installer/src/Prompts/Handlers/HandlerInterface.php (1)
resolvedMessage(155-155).vortex/installer/src/Prompts/Handlers/Profile.php (1)
resolvedMessage(93-99).vortex/installer/src/Prompts/Handlers/Webroot.php (1)
resolvedMessage(115-121)
.vortex/installer/src/Prompts/Handlers/Profile.php (5)
.vortex/installer/src/Prompts/Handlers/AbstractHandler.php (4)
resolvedValue(130-132)id(52-62)resolvedMessage(137-139)getResponseAsString(191-197).vortex/installer/src/Prompts/Handlers/HandlerInterface.php (3)
resolvedValue(138-138)id(19-19)resolvedMessage(155-155).vortex/installer/src/Prompts/Handlers/Starter.php (1)
Starter(10-150).vortex/installer/src/Prompts/Handlers/ProfileCustom.php (1)
ProfileCustom(9-86).vortex/installer/src/Utils/File.php (2)
File(10-102)replaceContentAsync(59-83)
.vortex/installer/tests/Unit/Handlers/AbstractPromptManagerTestCase.php (3)
.vortex/installer/src/Prompts/Handlers/Starter.php (1)
Starter(10-150).vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
id(52-62).vortex/installer/src/Prompts/Handlers/HandlerInterface.php (1)
id(19-19)
.vortex/installer/tests/Unit/Handlers/StarterPromptManagerTest.php (4)
.vortex/installer/src/Prompts/Handlers/Profile.php (1)
Profile(10-165).vortex/installer/src/Prompts/Handlers/Starter.php (1)
Starter(10-150).vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
id(52-62).vortex/installer/src/Prompts/Handlers/HandlerInterface.php (1)
id(19-19)
.vortex/installer/tests/Functional/Handlers/StarterInstallTest.php (6)
.vortex/installer/src/Prompts/Handlers/Starter.php (1)
Starter(10-150).vortex/installer/src/Prompts/PromptManager.php (2)
PromptManager(58-597)makeEnvName(413-415).vortex/installer/src/Utils/Env.php (2)
Env(7-245)put(24-26).vortex/installer/tests/Unit/Handlers/StarterPromptManagerTest.php (1)
CoversClass(12-47).vortex/installer/tests/Functional/Handlers/AbstractInstallTestCase.php (1)
AbstractInstallTestCase(19-101).vortex/installer/tests/Functional/FunctionalTestCase.php (1)
assertSutNotContains(139-154)
.vortex/installer/src/Prompts/Handlers/Internal.php (2)
.vortex/installer/src/Prompts/Handlers/Starter.php (1)
Starter(10-150).vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
id(52-62)
.vortex/tests/test.workflow.sh (3)
.vortex/tests/test.common.sh (1)
bats(28-37).vortex/tests/test.deployment.sh (1)
bats(29-38).vortex/tests/test.postbuild.sh (1)
bats(20-29)
.vortex/installer/src/Prompts/Handlers/Starter.php (2)
.vortex/installer/src/Utils/JsonManipulator.php (2)
JsonManipulator(10-76)fromFile(19-36).vortex/installer/src/Prompts/Handlers/AbstractHandler.php (1)
AbstractHandler(10-233)
.vortex/tests/bats/e2e/workflow.install.profile_drupalcms.bats (2)
.vortex/tests/bats/_helper.workflow.bash (6)
prepare_sut(7-39)assert_ahoy_build(73-130)assert_gitignore(132-162)assert_ahoy_lint(413-425)assert_ahoy_test(527-544)assert_ahoy_fe(753-777).vortex/tests/bats/_helper.bash (1)
assert_webpage_contains(1022-1028)
.vortex/installer/src/Prompts/PromptManager.php (5)
.vortex/installer/src/Prompts/Handlers/Profile.php (3)
Profile(10-165)resolvedValue(76-88)resolvedMessage(93-99).vortex/installer/src/Prompts/Handlers/AbstractHandler.php (3)
id(52-62)resolvedValue(130-132)resolvedMessage(137-139).vortex/installer/src/Prompts/Handlers/HandlerInterface.php (3)
id(19-19)resolvedValue(138-138)resolvedMessage(155-155).vortex/installer/src/Prompts/Handlers/Webroot.php (3)
Webroot(12-148)resolvedValue(98-110)resolvedMessage(115-121).vortex/installer/src/Utils/Tui.php (1)
info(42-44)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (13)
- GitHub Check: build (0)
- GitHub Check: build (1)
- GitHub Check: vortex-test-workflow (4)
- GitHub Check: vortex-test-workflow (2)
- GitHub Check: vortex-test-workflow (1)
- GitHub Check: vortex-test-workflow (3)
- GitHub Check: vortex-test-workflow (0)
- GitHub Check: vortex-test-deployment (0)
- GitHub Check: vortex-test-deployment (1)
- GitHub Check: vortex-test-common
- GitHub Check: vortex-test-installer (8.4)
- GitHub Check: vortex-test-installer (8.2)
- GitHub Check: vortex-test-installer (8.3)
🔇 Additional comments (18)
tests/behat/features/search.feature (3)
11-14: Fixtures updated for moderation — looks good.Using both status and moderation_state makes intent clear and aligns with the new published-only filtering.
25-27: Assertions match published-only expectation.Draft item correctly excluded; keep.
31-33: Scoped query checks are correct.Positive/negative assertions look precise.
web/modules/custom/ys_search/config/install/views.view.search.yml (1)
210-210: Teaser view mode mapping — verify bundle displays.Confirm all indexed bundles have a configured teaser matching prior output to avoid regressions.
.github/workflows/build-test-deploy.yml (1)
164-168: Fail-fast flips behavior; confirm impact on artifacts and diagnostics.With fail-fast: true, the first failing matrix leg cancels the other. This can drop logs/artifacts from the cancelled leg(s) and shorten diagnostics. Verify this is intentional for build, especially around artifact upload (per-instance) and subsequent troubleshooting needs.
.github/workflows/vortex-test-common.yml (1)
116-120: Batch expanded to 5 and fail-fast enabled — validate test runner coverage.Matrix now includes batch 4 and fail-fast: true. Ensure .vortex/tests/test.workflow.sh executes the new Drupal CMS batch and that cancellation won’t hide useful failures from other batches.
phpmd.xml (1)
17-18: Exclude recipes from PHPMD — sensible.Skipping /recipes/ mirrors contrib exclusions and reduces noise from vendor-like recipe code.
.gitignore (1)
34-34: Wording change looks good.The scaffold guidance comment is consistent with project style.
.vortex/installer/tests/Unit/Handlers/AbstractPromptManagerTestCase.php (1)
124-124: Default updated to LOAD_DATABASE_DEMO — aligned with Starter.Matches the new constant and Starter::default().
.vortex/tests/test.workflow.sh (1)
71-73: New case for Drupal CMS e2e — OK.Dedicated selector improves isolation.
.vortex/installer/src/Prompts/Handlers/HandlerInterface.php (1)
149-156: API change looks good; signature aligns with implementers.
The new$resolvedparameter is clear and consistent with AbstractHandler/Profile/Webroot..vortex/installer/src/Prompts/Handlers/Webroot.php (1)
115-118: Resolved-message implementation is correct.
Accepts$resolved, guards type, and formats the message. Matches interface change..vortex/installer/tests/Unit/Handlers/StarterPromptManagerTest.php (3)
7-7: Import for Profile is correct.
Needed for referencing path constant in expectations.
21-21: Updated constants in expectations are correct.
LOAD_DATABASE_DEMO and INSTALL_PROFILE_CORE align with Starter::options/default.Also applies to: 39-39
28-33: New Drupal CMS profile case looks right.
Covers resolved path propagation via Profile::id() => INSTALL_PROFILE_DRUPALCMS_PATH..vortex/installer/src/Prompts/PromptManager.php (2)
128-130: Good use of the new resolver for Profile.
Keeps the flow DRY and centralized.
153-154: Good reuse of resolver for Webroot.
Consistent with Profile handling..vortex/installer/src/Prompts/Handlers/Profile.php (1)
76-88: Resolution path looks correct.
Discovery wins; otherwise map Drupal CMS starter correctly via Starter constant.
| fail-fast: true | ||
| matrix: | ||
| batch: [0, 1] | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick (assertive)
Fail-fast for deployment tests — tradeoff check.
Ok if speed > parallel failure visibility. If you still want all batches’ logs even after one fails, keep fail-fast false here.
🤖 Prompt for AI Agents
.github/workflows/vortex-test-common.yml lines 186-189: the matrix step
currently sets fail-fast: true which aborts remaining batch jobs on the first
failure and prevents collecting logs from other batches; if you need logs and
results from all batches change fail-fast to false, commit that change, and
re-run the workflow to verify all batch jobs execute to completion so you can
inspect their logs even when one fails.
| public function resolvedMessage(array $responses, mixed $resolved): ?string { | ||
| if (is_string($resolved)) { | ||
| return sprintf('Profile will be set to "%s".', $resolved); | ||
| } | ||
|
|
||
| return NULL; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick (assertive)
Avoid logging “custom” as a final profile value.
Skip the message when the resolved value is the sentinel “custom” to avoid misleading output.
public function resolvedMessage(array $responses, mixed $resolved): ?string {
- if (is_string($resolved)) {
+ if (is_string($resolved)) {
+ if ($resolved === self::CUSTOM) {
+ return NULL;
+ }
return sprintf('Profile will be set to "%s".', $resolved);
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| public function resolvedMessage(array $responses, mixed $resolved): ?string { | |
| if (is_string($resolved)) { | |
| return sprintf('Profile will be set to "%s".', $resolved); | |
| } | |
| return NULL; | |
| } | |
| public function resolvedMessage(array $responses, mixed $resolved): ?string { | |
| if (is_string($resolved)) { | |
| if ($resolved === self::CUSTOM) { | |
| return NULL; | |
| } | |
| return sprintf('Profile will be set to "%s".', $resolved); | |
| } | |
| return NULL; | |
| } |
🤖 Prompt for AI Agents
.vortex/installer/src/Prompts/Handlers/Profile.php around lines 93 to 99: the
resolvedMessage currently returns a message for any string value, which can
incorrectly log the sentinel "custom"; update the logic to return NULL when the
resolved value is the string "custom" and only return the sprintf message for
other string values — i.e., check is_string($resolved) and if $resolved ===
'custom' return NULL, otherwise return the existing formatted message.
a3328d6 to
c90ee6a
Compare
Closes #1882
Summary by CodeRabbit
New Features
Refactor
Tests
Chores