refactor: site rename add to create - #113
Conversation
WalkthroughRenames site "add" to "create" across commands and playbooks, removes HelloCommand, makes SiteDTO repo/branch nullable, adds SiteRepository::update(), enhances SiteDeployCommand with repo/branch resolution and inventory updates, and standardizes messaging and CLI descriptions. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Possibly related PRs
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
.cursor/rules/00-main.mdc (1)
60-62: Tighten conversational prose in "Test later" section to imperative mood.Line 62 ("Tests are something we will focus on...") shifts to conversational explanation rather than maintaining the imperative directive tone required in rule files. Based on learnings, rule files should use imperative mood throughout.
Apply this diff to align with imperative mood:
### Test later -Don't run or create or update tests UNLESS explicitly instructed to do so. - -Tests are something we will focus on separately from building features. +Do not run, create, or update tests unless explicitly instructed.app/Console/Site/SiteHttpsCommand.php (1)
105-105: Inconsistent terminology: "re-add" should be "re-create".Line 105 still references "re-add the site" which is inconsistent with the PR's terminology refactoring from "add" to "create". For consistency, this should be updated to "re-create the site".
Apply this diff to maintain consistent terminology:
- $this->nay("Could not detect PHP version for '{$site->domain}' from server config; re-add the site or run server:info to debug."); + $this->nay("Could not detect PHP version for '{$site->domain}' from server config; re-create the site or run server:info to debug.");
🧹 Nitpick comments (3)
app/Console/Server/ServerDeleteCommand.php (1)
183-183: Terminology normalized for consistency.The change aligns the success message with the informational messages on lines 85 and 97, creating consistency within the command flow. While the command name and description still use "delete", the distinction between "delete" (the overall operation) and "remove from inventory" (the specific inventory action) appears intentional.
If full consistency is desired, consider updating line 18 as well:
- description: 'Delete a server from inventory' + description: 'Remove a server from inventory'app/Console/Site/SiteDeployCommand.php (1)
260-266: Consider conditional inclusion of repo/branch in replay payload.Per the learning about
commandReplay(): "only include conditional options if they were actually used." Sincerepoandbranchare now always included regardless of whether they came from stored values or CLI input, the replay command will always contain these options.If the intent is for users to replay with minimal options (relying on stored values), consider including
repo/branchonly when they were explicitly provided via CLI or prompted.$this->commandReplay('site:deploy', [ 'domain' => $site->domain, - 'repo' => $repo, - 'branch' => $branch, + ...($needsUpdate ? ['repo' => $repo, 'branch' => $branch] : []), 'keep-releases' => $keepReleases, 'yes' => true, ]);app/Console/Site/SiteCreateCommand.php (1)
180-191: Align validateServerReady docblock wording with “create” terminologyThe tightened Caddy availability check (
true === ($info['caddy']['available'] ?? false)) is a nice improvement, and the overall validation logic is straightforward.The docblock summary still says “ready to add site”, which is now out of sync with the command’s terminology. Consider updating for clarity:
- * Validate that server is ready to add site. + * Validate that server is ready to create a site.Also applies to: 193-206
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (18)
.cursor/rules/00-main.mdc(1 hunks)app/Console/HelloCommand.php(0 hunks)app/Console/Server/ServerAddCommand.php(2 hunks)app/Console/Server/ServerDeleteCommand.php(1 hunks)app/Console/Server/ServerInstallCommand.php(1 hunks)app/Console/Server/ServerListCommand.php(1 hunks)app/Console/Server/ServerProvisionDigitalOceanCommand.php(1 hunks)app/Console/Site/SiteCreateCommand.php(13 hunks)app/Console/Site/SiteDeleteCommand.php(5 hunks)app/Console/Site/SiteDeployCommand.php(15 hunks)app/Console/Site/SiteHttpsCommand.php(1 hunks)app/Console/Site/SiteListCommand.php(1 hunks)app/DTOs/SiteDTO.php(1 hunks)app/Repositories/SiteRepository.php(3 hunks)app/SymfonyApp.php(2 hunks)app/Traits/SitesTrait.php(10 hunks)playbooks/site-create.sh(2 hunks)playbooks/site-delete.sh(4 hunks)
💤 Files with no reviewable changes (1)
- app/Console/HelloCommand.php
🧰 Additional context used
📓 Path-based instructions (5)
**/*.php
📄 CodeRabbit inference engine (.cursor/rules/00-main.mdc)
**/*.php: Eliminate single-use methods: inline if called once
Cache computed values: initialize expensive calculations in constructor
Avoid method call overhead: direct property access when appropriate
Group related functions into comment-separated sections
Order alphabetically after grouping logically
**/*.php: Follow PSR-12 standard with strict types enabled and use PHP 8.x features (unions, match, attributes, readonly)
Use explicit return types with generics (e.g.,Collection<int, User>) for all functions and methods
Use dependency injection via Symfony patterns for all object dependencies
Use Symfony classes over native PHP functions (Filesystem, Process) for testability
Always use Yoda conditions: place constants/literals on the LEFT side of comparisons (e.g.,null === $value) to prevent accidental assignment
Always use braces for ALL control structures (if, else, elseif, for, foreach, while, do-while), even for single-line bodies
Use@varannotations to help PHPStan understand types it cannot infer, notassert()in production code
Always addusestatements for vendor packages and project classes; root namespace FQDNs acceptable for built-in exceptions (e.g.,\InvalidArgumentException)
Use$container->build(ClassName::class)for all object creation; use this except for DTOs, value objects, and pure data structures
Use constructor injection in production code and direct instantiation in tests for container access
All object dependencies must be declared in constructor signatures; NO circular dependencies allowed
Use minimalist DocBlock descriptions with parameters and return types for classes and functions; separate sections visually with one newline between headers/paragraphs
**/*.php: Services and Repositories must throw \RuntimeException with complete, actionable messages that include relevant context (paths, names, IDs, hosts) and are user-facing, not fragments
When catching and re-throwing exceptions in Services and Repositories, use t...
Files:
app/Console/Server/ServerInstallCommand.phpapp/Console/Server/ServerProvisionDigitalOceanCommand.phpapp/Console/Server/ServerListCommand.phpapp/DTOs/SiteDTO.phpapp/Console/Server/ServerDeleteCommand.phpapp/Console/Server/ServerAddCommand.phpapp/Console/Site/SiteDeleteCommand.phpapp/Console/Site/SiteListCommand.phpapp/Console/Site/SiteHttpsCommand.phpapp/Traits/SitesTrait.phpapp/Console/Site/SiteCreateCommand.phpapp/Console/Site/SiteDeployCommand.phpapp/Repositories/SiteRepository.phpapp/SymfonyApp.php
**/*Command.php
📄 CodeRabbit inference engine (.cursor/rules/01-architecture.mdc)
Command Layer: handle user interaction and orchestrate Services; contain NO business logic, NO duplicate orchestration, NO invocation of other commands
**/*Command.php: Command layer (Commands and Orchestration Traits) must display caught \RuntimeException messages directly without adding redundant prefixes like 'Failed to...'
Only add contextual information to exception displays in Command layer when necessary: raw output for debugging, actionable troubleshooting steps, or when the exception message is too technical/generic
Files:
app/Console/Server/ServerInstallCommand.phpapp/Console/Server/ServerProvisionDigitalOceanCommand.phpapp/Console/Server/ServerListCommand.phpapp/Console/Server/ServerDeleteCommand.phpapp/Console/Server/ServerAddCommand.phpapp/Console/Site/SiteDeleteCommand.phpapp/Console/Site/SiteListCommand.phpapp/Console/Site/SiteHttpsCommand.phpapp/Console/Site/SiteCreateCommand.phpapp/Console/Site/SiteDeployCommand.php
**/{*Command,*Service}.php
📄 CodeRabbit inference engine (.cursor/rules/01-architecture.mdc)
Only Commands perform console I/O using SymfonyStyle; Services return exceptions/data for Commands to display
Files:
app/Console/Server/ServerInstallCommand.phpapp/Console/Server/ServerProvisionDigitalOceanCommand.phpapp/Console/Server/ServerListCommand.phpapp/Console/Server/ServerDeleteCommand.phpapp/Console/Server/ServerAddCommand.phpapp/Console/Site/SiteDeleteCommand.phpapp/Console/Site/SiteListCommand.phpapp/Console/Site/SiteHttpsCommand.phpapp/Console/Site/SiteCreateCommand.phpapp/Console/Site/SiteDeployCommand.php
**/*.{sh,bash}
📄 CodeRabbit inference engine (.cursor/rules/05-bash.mdc)
**/*.{sh,bash}: Use[[ ... ]]for conditionals instead of[ ... ]ortest
Use$(...)for command substitution instead of backticks
Use((...))and$((...))for math operations, never uselet
Define functions withoutfunctionkeyword and always uselocalfor variables within functions
Placethenon the same line asif, anddoon the same line aswhilein block statements
Prefer parameter expansion over external commands (e.g., use${0##*/}instead of$(basename "$0"))
Use double quotes for parameter expansions and single quotes for string literals
Exception: Variables controlled by the script (not user input) may be unquoted in[[ ... ]]contexts
Use bash arrays instead of space-separated strings, and use quoted array expansion"${array[@]}"
Always check commands that can fail with|| exitor similar error handling
Useset -o pipefailto catch errors in pipelines
Do not useset -e(errexit); prefer explicit error checking instead
Never useevaldue to security risks and inability to perform static analysis
Use redirection or built-in read for reading files, stream withwhile IFS= readloops instead of loading entire files
Never parselsoutput for listing files; use shell globs instead
Use tabs for indentation in Bash scripts
Maintain maximum line length of 80 columns in Bash scripts
Use semicolons only in control statements likeif true; then
Maintain maximum 1 blank line between sections in Bash scripts
Use shebang#!/usr/bin/env bashat the start of Bash scripts
Files:
playbooks/site-delete.shplaybooks/site-create.sh
**/*Trait.php
📄 CodeRabbit inference engine (.cursor/rules/04-exceptions.mdc)
**/*Trait.php: Input Validation Traits must provide a validateNameInput() method that returns ?string (error message or null) for prompts/CLI options validation
Heavy I/O Validation Traits must provide a validate*() method that throws \RuntimeException with complete error messages instead of returning ?string
Files:
app/Traits/SitesTrait.php
🧠 Learnings (29)
📚 Learning: 2025-12-03T12:36:20.794Z
Learnt from: CR
Repo: loadinglucian/deployer PR: 0
File: .cursor/rules/06-playbooks.mdc:0-0
Timestamp: 2025-12-03T12:36:20.794Z
Learning: Applies to **/*playbook*.sh : Use `main()` function as the entry point with `main "$@"` at the bottom of playbooks
Applied to files:
playbooks/site-delete.shplaybooks/site-create.sh
📚 Learning: 2025-12-03T12:36:20.794Z
Learnt from: CR
Repo: loadinglucian/deployer PR: 0
File: .cursor/rules/06-playbooks.mdc:0-0
Timestamp: 2025-12-03T12:36:20.794Z
Learning: Applies to **/*playbook*.sh : Use idempotent checks before modifying resources (e.g., `if ! command -v`, `if [[ ! -d`, `if ! systemctl is-enabled`)
Applied to files:
playbooks/site-delete.shplaybooks/site-create.sh
📚 Learning: 2025-12-03T12:36:20.794Z
Learnt from: CR
Repo: loadinglucian/deployer PR: 0
File: .cursor/rules/06-playbooks.mdc:0-0
Timestamp: 2025-12-03T12:36:20.794Z
Learning: Applies to **/*playbook*.sh : Support both Ubuntu and Debian distributions using `case $DEPLOYER_DISTRO` statements only when distributions differ
Applied to files:
playbooks/site-delete.shplaybooks/site-create.sh
📚 Learning: 2025-12-03T12:36:20.794Z
Learnt from: CR
Repo: loadinglucian/deployer PR: 0
File: .cursor/rules/06-playbooks.mdc:0-0
Timestamp: 2025-12-03T12:36:20.794Z
Learning: Applies to **/*playbook*.sh : Validate `DEPLOYER_OUTPUT_FILE` environment variable before any work in all playbooks
Applied to files:
playbooks/site-delete.sh
📚 Learning: 2025-12-03T12:36:20.794Z
Learnt from: CR
Repo: loadinglucian/deployer PR: 0
File: .cursor/rules/06-playbooks.mdc:0-0
Timestamp: 2025-12-03T12:36:20.794Z
Learning: Applies to **/*playbook*.sh : Write parsable YAML output to `DEPLOYER_OUTPUT_FILE` with error checking on write operations
Applied to files:
playbooks/site-delete.shplaybooks/site-create.sh
📚 Learning: 2025-12-03T12:36:20.794Z
Learnt from: CR
Repo: loadinglucian/deployer PR: 0
File: .cursor/rules/06-playbooks.mdc:0-0
Timestamp: 2025-12-03T12:36:20.794Z
Learning: Applies to **/*playbook*.sh : Group related helper functions with comment headers using format `# ---- <section_name> ----` or `#
# Helper Functions
# ----`
Applied to files:
playbooks/site-create.sh
📚 Learning: 2025-12-03T12:36:20.794Z
Learnt from: CR
Repo: loadinglucian/deployer PR: 0
File: .cursor/rules/06-playbooks.mdc:0-0
Timestamp: 2025-12-03T12:36:20.794Z
Learning: Applies to **/*playbook*.sh : Export `DEBIAN_FRONTEND=noninteractive` at the top of playbook files
Applied to files:
playbooks/site-create.sh
📚 Learning: 2025-12-03T12:36:20.794Z
Learnt from: CR
Repo: loadinglucian/deployer PR: 0
File: .cursor/rules/06-playbooks.mdc:0-0
Timestamp: 2025-12-03T12:36:20.794Z
Learning: Applies to **/*playbook*.sh : Provisioning playbooks must validate `DEPLOYER_DISTRO` and `DEPLOYER_PERMS` environment variables in addition to `DEPLOYER_OUTPUT_FILE`
Applied to files:
playbooks/site-create.sh
📚 Learning: 2025-12-03T12:36:20.794Z
Learnt from: CR
Repo: loadinglucian/deployer PR: 0
File: .cursor/rules/06-playbooks.mdc:0-0
Timestamp: 2025-12-03T12:36:20.794Z
Learning: Applies to **/*playbook*.sh : Use shebang `#!/usr/bin/env bash` at the top of all playbook files
Applied to files:
playbooks/site-create.sh
📚 Learning: 2025-12-03T12:36:20.794Z
Learnt from: CR
Repo: loadinglucian/deployer PR: 0
File: .cursor/rules/06-playbooks.mdc:0-0
Timestamp: 2025-12-03T12:36:20.794Z
Learning: Applies to **/*playbook*.sh : Use `-y -q` flags with apt package manager and `--batch --yes` flags with GPG operations for non-interactive execution
Applied to files:
playbooks/site-create.sh
📚 Learning: 2025-12-03T12:36:20.794Z
Learnt from: CR
Repo: loadinglucian/deployer PR: 0
File: .cursor/rules/06-playbooks.mdc:0-0
Timestamp: 2025-12-03T12:36:20.794Z
Learning: Playbooks are idempotent, non-interactive bash scripts that execute one or more related tasks and receive context via environment variables
Applied to files:
playbooks/site-create.sh
📚 Learning: 2025-12-03T21:59:13.882Z
Learnt from: CR
Repo: loadinglucian/deployer PR: 0
File: .cursor/rules/03-commands.mdc:0-0
Timestamp: 2025-12-03T21:59:13.882Z
Learning: Applies to **/Command.php : Command option naming: use --server for selecting existing servers, --name for defining new resource names, --yes/-y for skip confirmation, --force/-f for skip type-to-confirm
Applied to files:
app/Console/Server/ServerListCommand.phpapp/Console/Server/ServerDeleteCommand.phpapp/Console/Server/ServerAddCommand.phpapp/Console/Site/SiteCreateCommand.phpapp/Console/Site/SiteDeployCommand.phpapp/SymfonyApp.php
📚 Learning: 2025-12-03T21:59:13.882Z
Learnt from: CR
Repo: loadinglucian/deployer PR: 0
File: .cursor/rules/03-commands.mdc:0-0
Timestamp: 2025-12-03T21:59:13.882Z
Learning: Applies to **/Command.php : Detect and reject conflicting option combinations (e.g., --generate-deploy-key and --custom-deploy-key together)
Applied to files:
app/Console/Site/SiteCreateCommand.phpapp/Console/Site/SiteDeployCommand.php
📚 Learning: 2025-12-03T21:59:13.882Z
Learnt from: CR
Repo: loadinglucian/deployer PR: 0
File: .cursor/rules/03-commands.mdc:0-0
Timestamp: 2025-12-03T21:59:13.882Z
Learning: Applies to **/Command.php : Use OPTIONS only, never ARGUMENTS, to enable getOptionOrPrompt() functionality in Symfony Console commands
Applied to files:
app/Console/Site/SiteCreateCommand.php
📚 Learning: 2025-12-03T21:59:13.882Z
Learnt from: CR
Repo: loadinglucian/deployer PR: 0
File: .cursor/rules/03-commands.mdc:0-0
Timestamp: 2025-12-03T21:59:13.882Z
Learning: Applies to **/Command.php : Multiselect CLI options: validate CLI-provided values against allowed options and reject unknown options
Applied to files:
app/Console/Site/SiteCreateCommand.php
📚 Learning: 2025-12-03T12:36:37.985Z
Learnt from: CR
Repo: loadinglucian/deployer PR: 0
File: .cursor/rules/rules.mdc:0-0
Timestamp: 2025-12-03T12:36:37.985Z
Learning: Before committing rule changes, remove outdated file references, check for duplication, verify no contradictions, test code examples, and run token count comparison
Applied to files:
.cursor/rules/00-main.mdc
📚 Learning: 2025-12-03T12:36:37.985Z
Learnt from: CR
Repo: loadinglucian/deployer PR: 0
File: .cursor/rules/rules.mdc:0-0
Timestamp: 2025-12-03T12:36:37.985Z
Learning: Applies to **/*rules*.{md,mdc} : Avoid repetitive CRITICAL/IMMUTABLE warnings in rule files
Applied to files:
.cursor/rules/00-main.mdc
📚 Learning: 2025-12-03T12:36:37.985Z
Learnt from: CR
Repo: loadinglucian/deployer PR: 0
File: .cursor/rules/rules.mdc:0-0
Timestamp: 2025-12-03T12:36:37.985Z
Learning: Applies to **/*rules*.{md,mdc} : Verify all mdc:// references point to existing files in rule files
Applied to files:
.cursor/rules/00-main.mdc
📚 Learning: 2025-12-03T12:36:37.985Z
Learnt from: CR
Repo: loadinglucian/deployer PR: 0
File: .cursor/rules/rules.mdc:0-0
Timestamp: 2025-12-03T12:36:37.985Z
Learning: Applies to **/*rules*.{md,mdc} : Include single 'All rules MANDATORY' statement per rule file
Applied to files:
.cursor/rules/00-main.mdc
📚 Learning: 2025-12-03T12:36:37.985Z
Learnt from: CR
Repo: loadinglucian/deployer PR: 0
File: .cursor/rules/rules.mdc:0-0
Timestamp: 2025-12-03T12:36:37.985Z
Learning: Applies to **/*rules*.{md,mdc} : Remove 'Benefits', 'Why This Matters', and 'Key Benefits' sections from rule files
Applied to files:
.cursor/rules/00-main.mdc
📚 Learning: 2025-12-03T12:36:37.985Z
Learnt from: CR
Repo: loadinglucian/deployer PR: 0
File: .cursor/rules/rules.mdc:0-0
Timestamp: 2025-12-03T12:36:37.985Z
Learning: Applies to **/*rules*.{md,mdc} : Use imperative mood in rule files, not conversational prose
Applied to files:
.cursor/rules/00-main.mdc
📚 Learning: 2025-12-03T12:36:37.985Z
Learnt from: CR
Repo: loadinglucian/deployer PR: 0
File: .cursor/rules/rules.mdc:0-0
Timestamp: 2025-12-03T12:36:37.985Z
Learning: Applies to **/*rules*.{md,mdc} : Remove references to deleted files immediately from rule files
Applied to files:
.cursor/rules/00-main.mdc
📚 Learning: 2025-12-03T12:36:37.985Z
Learnt from: CR
Repo: loadinglucian/deployer PR: 0
File: .cursor/rules/rules.mdc:0-0
Timestamp: 2025-12-03T12:36:37.985Z
Learning: Applies to **/*rules*.{md,mdc} : Do not copy third-party documentation verbatim in rule files; summarize key points only
Applied to files:
.cursor/rules/00-main.mdc
📚 Learning: 2025-12-03T12:36:37.985Z
Learnt from: CR
Repo: loadinglucian/deployer PR: 0
File: .cursor/rules/rules.mdc:0-0
Timestamp: 2025-12-03T12:36:37.985Z
Learning: Applies to **/*rules*.{md,mdc} : Maintain single source of truth per concept across rule files; if a rule appears in multiple contexts, pick primary location
Applied to files:
.cursor/rules/00-main.mdc
📚 Learning: 2025-12-03T12:34:49.483Z
Learnt from: CR
Repo: loadinglucian/deployer PR: 0
File: .cursor/rules/00-main.mdc:0-0
Timestamp: 2025-12-03T12:34:49.483Z
Learning: Code should appear written by single person: naming, parameter precedence, logic flow, organization
Applied to files:
.cursor/rules/00-main.mdc
📚 Learning: 2025-12-03T12:34:49.483Z
Learnt from: CR
Repo: loadinglucian/deployer PR: 0
File: .cursor/rules/00-main.mdc:0-0
Timestamp: 2025-12-03T12:34:49.483Z
Learning: Review surrounding code for reusable patterns
Applied to files:
.cursor/rules/00-main.mdc
📚 Learning: 2025-12-03T12:34:49.483Z
Learnt from: CR
Repo: loadinglucian/deployer PR: 0
File: .cursor/rules/00-main.mdc:0-0
Timestamp: 2025-12-03T12:34:49.483Z
Learning: Applies to **/*.php : Group related functions into comment-separated sections
Applied to files:
.cursor/rules/00-main.mdc
📚 Learning: 2025-12-03T21:58:53.505Z
Learnt from: CR
Repo: loadinglucian/deployer PR: 0
File: .cursor/rules/01-architecture.mdc:0-0
Timestamp: 2025-12-03T21:58:53.505Z
Learning: Applies to **/*.php : Always use braces for ALL control structures (if, else, elseif, for, foreach, while, do-while), even for single-line bodies
Applied to files:
.cursor/rules/00-main.mdc
📚 Learning: 2025-12-03T21:59:13.882Z
Learnt from: CR
Repo: loadinglucian/deployer PR: 0
File: .cursor/rules/03-commands.mdc:0-0
Timestamp: 2025-12-03T21:59:13.882Z
Learning: Applies to **/Command.php : In commandReplay(), only include conditional options if they were actually used (e.g., only include --custom-deploy-key if user selected custom path)
Applied to files:
app/Console/Site/SiteDeployCommand.php
🧬 Code graph analysis (10)
app/Console/Server/ServerProvisionDigitalOceanCommand.php (1)
app/Contracts/BaseCommand.php (1)
ul(232-240)
playbooks/site-delete.sh (1)
playbooks/helpers.sh (1)
run_cmd(19-25)
app/DTOs/SiteDTO.php (1)
app/DTOs/ServerDTO.php (1)
__construct(10-20)
app/Console/Server/ServerDeleteCommand.php (1)
app/Contracts/BaseCommand.php (1)
yay(206-209)
app/Console/Server/ServerAddCommand.php (1)
app/Contracts/BaseCommand.php (1)
ul(232-240)
app/Console/Site/SiteDeleteCommand.php (1)
app/Contracts/BaseCommand.php (2)
warn(214-217)yay(206-209)
app/Traits/SitesTrait.php (4)
app/Contracts/BaseCommand.php (4)
info(198-201)ul(232-240)nay(222-225)out(264-267)app/Repositories/SiteRepository.php (1)
findByDomain(101-112)app/Services/IOService.php (1)
out(57-74)app/DTOs/SiteDTO.php (1)
SiteDTO(7-24)
app/Console/Site/SiteCreateCommand.php (4)
app/Contracts/BaseCommand.php (3)
BaseCommand(30-355)ul(232-240)commandReplay(305-354)app/Traits/ServersTrait.php (1)
selectServer(129-165)app/Traits/SitesTrait.php (1)
displaySiteDeets(110-127)app/Traits/PlaybooksTrait.php (1)
executePlaybookSilently(37-52)
app/Console/Site/SiteDeployCommand.php (6)
app/DTOs/SiteDTO.php (1)
SiteDTO(7-24)app/Contracts/BaseCommand.php (2)
info(198-201)warn(214-217)app/Repositories/SiteRepository.php (1)
update(75-93)app/Services/GitService.php (2)
detectRemoteUrl(30-36)detectCurrentBranch(44-50)app/Services/IOService.php (2)
getValidatedOptionOrPrompt(211-233)promptText(251-267)app/Traits/SitesTrait.php (2)
validateSiteRepo(198-225)validateSiteBranch(180-191)
app/Repositories/SiteRepository.php (3)
app/DTOs/SiteDTO.php (1)
SiteDTO(7-24)app/Repositories/ServerRepository.php (1)
assertInventoryLoaded(145-150)app/Services/InventoryService.php (1)
set(54-60)
🪛 PHPMD (2.15.0)
app/Console/Site/SiteCreateCommand.php
149-149: Avoid unused local variables such as '$displayUrl'. (undefined)
(UnusedLocalVariable)
🔇 Additional comments (32)
.cursor/rules/00-main.mdc (2)
44-52: File Operations section is well-structured.Terminal commands follow the imperative mood and provide clear, practical guidance for file management. The organization into a dedicated subsection aligns with the codebase philosophy of grouping related guidance. Based on learnings, this section meets standards for rule file content.
57-58: Execution Protocol expansion clarifies process steps.The addition of "STEP BY STEP" and "ACT" steps creates a more complete procedure flow. Steps are concise and directive.
app/Console/Site/SiteHttpsCommand.php (1)
96-97: LGTM! Terminology correctly updated.The message correctly reflects the refactoring from "add" to "create" terminology. The guidance is clear and actionable for users.
app/Console/Server/ServerProvisionDigitalOceanCommand.php (1)
174-177: LGTM! Enhanced user guidance after provisioning.The addition of usage hints after successful provisioning improves the user experience by clearly indicating the next steps. The implementation is consistent with similar changes in
ServerAddCommand.php.app/Console/Server/ServerInstallCommand.php (1)
159-159: LGTM! Terminology updated to reflect site:create command.The change from
site:addtosite:createis consistent with the PR's refactoring objectives.playbooks/site-create.sh (2)
4-6: LGTM! Playbook description updated to reflect "create" terminology.The header comments now correctly reference "Site Create Playbook" instead of "Site Add Playbook", aligning with the broader terminology changes in this PR.
114-114: LGTM! User-facing message improved for clarity.The change from "Deploy your application with" to "Deploy your new site with" provides clearer context about what is being deployed.
app/Console/Site/SiteListCommand.php (1)
16-16: LGTM! Command description made more concise.Removing "the" from the description improves consistency with similar commands across the codebase.
app/Console/Server/ServerListCommand.php (1)
17-17: LGTM! Command description made more concise.Removing "the" from the description improves consistency with similar commands across the codebase.
playbooks/site-delete.sh (1)
6-10: LGTM! Terminology consistently updated from "remove" to "delete".The function renames and message updates throughout the script are consistent:
remove_caddy_vhost→delete_caddy_vhostremove_site_files→delete_site_files- All call sites updated correctly
- User-facing messages now use "Deleting" instead of "Removing"
The changes align with the PR's objective to standardize terminology across the codebase.
Also applies to: 39-53, 70-84, 94-96
app/Console/Server/ServerAddCommand.php (2)
20-20: LGTM! Command description made more concise.Removing "the" from the description improves consistency with other list commands in the codebase.
99-102: LGTM! Enhanced user guidance after adding server.The addition of usage hints after successful server addition improves UX by clearly indicating the next steps. The implementation is consistent with the pattern used in
ServerProvisionDigitalOceanCommand.php.app/Traits/SitesTrait.php (8)
40-40: LGTM! PHPDoc formatting improved.Minor spacing adjustments in PHPDoc comments improve consistency.
Also applies to: 66-66
53-55: LGTM! Yoda condition applied and command reference updated.The changes correctly:
- Apply Yoda condition (
0 === count($allSites)) per coding guidelines- Update command reference from
site:addtosite:create
98-98: LGTM! Yoda condition applied correctly.Using
null === $sitefollows the coding guideline to place constants/literals on the left side of comparisons.
117-123: LGTM! Display logic updated for nullable fields.The conditional display of Repo and Branch fields aligns with the SiteDTO changes that made these fields nullable. This prevents displaying null values in the site details.
147-154: LGTM! Yoda conditions applied correctly.Both comparisons now use Yoda conditions as per coding guidelines:
- Line 147: Expression reformatted for clarity
- Line 154:
null !== $existingplaces the constant on the left
186-186: LGTM! Yoda conditions applied to validation logic.Both empty string checks now use Yoda conditions (
'' === trim(...)) per coding guidelines.Also applies to: 204-204
248-251: LGTM! Validation updated with Yoda condition and new terminology.The changes correctly:
- Apply Yoda condition (
0 !== $result['exit_code'])- Update messaging from "added" to "created"
- Update command reference from
site:addtosite:create
271-271: LGTM! Path construction spacing normalized.The path building logic is now more consistent:
- Direct concatenation with proper spacing
getSiteSharedPath()reusesgetSiteRootPath()for DRY principleAlso applies to: 279-279
app/DTOs/SiteDTO.php (1)
13-20: LGTM!The nullable
repoandbranchproperties align with theServerDTOpattern and the updated site creation flow where git details are optional at creation time. DocBlock accurately documents the nullable semantics.app/SymfonyApp.php (1)
19-19: LGTM!The import and command registration are consistent with the rename from
SiteAddCommandtoSiteCreateCommand.Also applies to: 151-151
app/Console/Site/SiteDeleteCommand.php (1)
102-178: LGTM!The terminology refactor from "remove" to "delete" for server operations and "remove" for inventory operations provides clear semantic distinction. The variable renaming from
removedFromServertodeletedFromServeris consistently applied throughout the execution flow.app/Repositories/SiteRepository.php (2)
69-93: LGTM!The new
update()method follows the established repository pattern: it asserts inventory is loaded, searches by domain, updates in-place viadehydrateSiteDTO(), and throws aRuntimeExceptionwith an actionable message when the site is not found. This aligns with theServerRepositorypattern shown in relevant snippets.
200-215: LGTM!Conditional inclusion of
repoandbranchin the dehydrated array prevents storingnullvalues in inventory, keeping the storage representation clean. This pairs well withhydrateSiteDTO()defaulting missing keys tonull.app/Console/Site/SiteDeployCommand.php (4)
47-48: LGTM!New
--repoand--branchoptions follow the established naming convention and enable CLI-driven deployment without stored git configuration.
275-347: Verify CLI override behavior for stored repo/branch values.The
resolveRepoAndBranch()logic allows CLI options (--repo/--branch) to override stored values without settingneedsUpdate, meaning temporary overrides won't persist to inventory. This appears intentional for one-off deployments to alternate repos/branches.Confirm this is the desired behavior—if CLI overrides should persist, the
needsUpdateflag should be set when a CLI value differs from the stored value.
234-240: LGTM!Catching
RuntimeExceptionfrom the inventory update and logging a warning (rather than failing the deployment) is appropriate—the deployment itself succeeded, and inventory persistence is a secondary concern.
459-461: Defensive null check is acceptable but should be unreachable.Given the flow—
resolveRepoAndBranch()either populatesrepo/branchor returnsnull(causing early exit), and the newSiteDTOis constructed with these values—this null check should never trigger. The early return of[](no missing hooks) is safe as defensive coding, though it could theoretically mask issues if null values somehow slip through.app/Console/Site/SiteCreateCommand.php (3)
18-23: Command rename and execution flow look consistentRenaming to
site:create, updating the heading to “Create New Site”, adding thenull === $server->infoguard, and short‑circuiting onnull === $siteInfoall align with the new “create” semantics and improve robustness without changing behavior in unexpected ways. InstantiatingSiteDTOwithrepo: nullandbranch: nullmatches the nullable DTO shape introduced elsewhere.Also applies to: 51-52, 57-60, 71-80, 85-90, 91-107
220-236: PHP version selection and validation logic is solidExtracting installed PHP versions in a backward‑compatible way, auto‑selecting when only one exists, preferring the configured default when present, and finally validating the CLI‑provided
--php-versionagainst$installedPhpVersionsgives a clear and predictable flow. Using strictin_array(..., true)and Yoda comparison (1 === count(...)) matches the coding guidelines.Also applies to: 237-247, 251-255, 256-267, 270-275
281-287: gatherSiteInfo flow and typing match the new Git‑less site modelThe updated return shape (
domain,phpVersion,wwwMode) and nullability are consistent with the new model. Domain validation/normalization, guarded WWW mode selection with explicit validation, and delegating PHP version selection toselectPhpVersion()all look correct. The early returns onnull === $domain/null === $wwwModecleanly handle user cancellations or validation failures without leaking partial state.Also applies to: 289-303, 312-327, 331-333, 339-349
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (3)
app/Console/Site/SiteCreateCommand.php (3)
57-60: Server selection and readiness checks are sound; update docblock wordingShort‑circuiting
is_int($server)avoids property access on error codes, andvalidateServerReady()cleanly enforces the Caddy/PHP preconditions with a singleCommand::FAILUREexit path. The docblock still says “add site” though; consider updating it to reflect thesite:createrename:- * Validate that server is ready to add site. + * Validate that server is ready to create a site.Also applies to: 71-80, 186-205
85-96: Site info wiring and inventory write align with nullable repo/branch
gatherSiteInfo()’s nullable return is handled correctly inexecute(),SiteDTOis constructed withrepo: null/branch: nullin line with the updated DTO anddisplaySiteDeets(), and the try/catch around$this->sites->create($site)keeps the command layer limited to showing theRuntimeExceptionmessage. If you want the success copy to mirror the create wording, you could slightly tweak the message:- $this->yay("Site '{$domain}' added to inventory"); + $this->yay("Site '{$domain}' created on server and added to inventory");Also applies to: 101-107, 135-143
111-125: Playbook invocation and DNS next steps are coherent; optional www‑mode hintsThe
site-createplaybook call with distro/perms/domain/PHP version/WWW mode looks correct, and the DNS checklist is concise and uses the server host consistently with no unused locals left over from the earlier$displayUrlapproach. As a small UX enhancement, you could tailor the DNS text to explain the canonical URL based on$wwwMode, for example:- $this->ul([ - 'Point <fg=cyan>@</> (root) to <fg=cyan>' . $server->host . '</>', - 'Point <fg=cyan>www</> to <fg=cyan>' . $server->host . '</>', - 'Run <fg=cyan>site:https</> to enable HTTPS once you have your DNS records set up', - 'Deploy your new site with <fg=cyan>site:deploy</>' - ]); + $dnsLines = [ + 'Point <fg=cyan>@</> (root) to <fg=cyan>' . $server->host . '</>', + 'Point <fg=cyan>www</> to <fg=cyan>' . $server->host . '</>', + 'Run <fg=cyan>site:https</> to enable HTTPS once you have your DNS records set up', + 'Deploy your new site with <fg=cyan>site:deploy</>', + ]; + + if ('redirect-to-www' === $wwwMode) { + $dnsLines[] = 'Your canonical URL will be <fg=cyan>www.' . $domain . '</>; non-www will redirect there.'; + } else { + $dnsLines[] = 'Your canonical URL will be <fg=cyan>' . $domain . '</>; www will redirect there.'; + } + + $this->ul($dnsLines);Also applies to: 149-156
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
app/Console/Site/SiteCreateCommand.php(13 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.php
📄 CodeRabbit inference engine (.cursor/rules/00-main.mdc)
**/*.php: Eliminate single-use methods: inline if called once
Cache computed values: initialize expensive calculations in constructor
Avoid method call overhead: direct property access when appropriate
Group related functions into comment-separated sections
Order alphabetically after grouping logically
**/*.php: Follow PSR-12 standard with strict types enabled and use PHP 8.x features (unions, match, attributes, readonly)
Use explicit return types with generics (e.g.,Collection<int, User>) for all functions and methods
Use dependency injection via Symfony patterns for all object dependencies
Use Symfony classes over native PHP functions (Filesystem, Process) for testability
Always use Yoda conditions: place constants/literals on the LEFT side of comparisons (e.g.,null === $value) to prevent accidental assignment
Always use braces for ALL control structures (if, else, elseif, for, foreach, while, do-while), even for single-line bodies
Use@varannotations to help PHPStan understand types it cannot infer, notassert()in production code
Always addusestatements for vendor packages and project classes; root namespace FQDNs acceptable for built-in exceptions (e.g.,\InvalidArgumentException)
Use$container->build(ClassName::class)for all object creation; use this except for DTOs, value objects, and pure data structures
Use constructor injection in production code and direct instantiation in tests for container access
All object dependencies must be declared in constructor signatures; NO circular dependencies allowed
Use minimalist DocBlock descriptions with parameters and return types for classes and functions; separate sections visually with one newline between headers/paragraphs
**/*.php: Services and Repositories must throw \RuntimeException with complete, actionable messages that include relevant context (paths, names, IDs, hosts) and are user-facing, not fragments
When catching and re-throwing exceptions in Services and Repositories, use t...
Files:
app/Console/Site/SiteCreateCommand.php
**/*Command.php
📄 CodeRabbit inference engine (.cursor/rules/01-architecture.mdc)
Command Layer: handle user interaction and orchestrate Services; contain NO business logic, NO duplicate orchestration, NO invocation of other commands
**/*Command.php: Command layer (Commands and Orchestration Traits) must display caught \RuntimeException messages directly without adding redundant prefixes like 'Failed to...'
Only add contextual information to exception displays in Command layer when necessary: raw output for debugging, actionable troubleshooting steps, or when the exception message is too technical/generic
Files:
app/Console/Site/SiteCreateCommand.php
**/{*Command,*Service}.php
📄 CodeRabbit inference engine (.cursor/rules/01-architecture.mdc)
Only Commands perform console I/O using SymfonyStyle; Services return exceptions/data for Commands to display
Files:
app/Console/Site/SiteCreateCommand.php
🧠 Learnings (4)
📚 Learning: 2025-12-03T21:59:13.882Z
Learnt from: CR
Repo: loadinglucian/deployer PR: 0
File: .cursor/rules/03-commands.mdc:0-0
Timestamp: 2025-12-03T21:59:13.882Z
Learning: Applies to **/Command.php : Command option naming: use --server for selecting existing servers, --name for defining new resource names, --yes/-y for skip confirmation, --force/-f for skip type-to-confirm
Applied to files:
app/Console/Site/SiteCreateCommand.php
📚 Learning: 2025-12-03T21:59:13.882Z
Learnt from: CR
Repo: loadinglucian/deployer PR: 0
File: .cursor/rules/03-commands.mdc:0-0
Timestamp: 2025-12-03T21:59:13.882Z
Learning: Applies to **/Command.php : Detect and reject conflicting option combinations (e.g., --generate-deploy-key and --custom-deploy-key together)
Applied to files:
app/Console/Site/SiteCreateCommand.php
📚 Learning: 2025-12-03T21:59:13.882Z
Learnt from: CR
Repo: loadinglucian/deployer PR: 0
File: .cursor/rules/03-commands.mdc:0-0
Timestamp: 2025-12-03T21:59:13.882Z
Learning: Applies to **/Command.php : Use OPTIONS only, never ARGUMENTS, to enable getOptionOrPrompt() functionality in Symfony Console commands
Applied to files:
app/Console/Site/SiteCreateCommand.php
📚 Learning: 2025-12-03T21:59:13.882Z
Learnt from: CR
Repo: loadinglucian/deployer PR: 0
File: .cursor/rules/03-commands.mdc:0-0
Timestamp: 2025-12-03T21:59:13.882Z
Learning: Applies to **/Command.php : Multiselect CLI options: validate CLI-provided values against allowed options and reject unknown options
Applied to files:
app/Console/Site/SiteCreateCommand.php
🧬 Code graph analysis (1)
app/Console/Site/SiteCreateCommand.php (4)
app/Contracts/BaseCommand.php (6)
BaseCommand(30-355)h1(171-179)info(198-201)yay(206-209)ul(232-240)commandReplay(305-354)app/Traits/ServersTrait.php (1)
selectServer(129-165)app/Traits/SitesTrait.php (1)
displaySiteDeets(110-127)app/Traits/PlaybooksTrait.php (1)
executePlaybookSilently(37-52)
🔇 Additional comments (3)
app/Console/Site/SiteCreateCommand.php (3)
19-22: Command rename and CLI surface are consistent with conventionsThe AsCommand name/description,
configure()options, H1 label, andcommandReplay()all usesite:createand “Create New Site”, and you rely solely on options (including--server) with no arguments, which matches the command rules and option‑naming guidance. Based on learnings, this aligns with the expected command option conventions.Also applies to: 32-41, 51-51, 162-167
233-237: PHP version selection handles edge cases and validates CLI input
selectPhpVersion()fails withCommand::FAILUREwhen no versions are installed, auto‑selects when only one is available, prefers the configured default (or newest) when prompting, and then validates any--php-versionvalue against the discovered list with a clear error if it’s invalid; this fits well with the validated‑option guidance from the command rules.Also applies to: 239-242, 245-252, 262-268
281-299: gatherSiteInfo() contract and validation look consistent with the new modelThe updated return type
{domain, phpVersion, wwwMode}|nullmatches whatexecute()actually consumes, early null checks cleanly propagate abort/validation failures, and normalizing the domain before further use keeps downstream behaviour consistent; no issues noticed here.Also applies to: 304-325, 327-345
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
app/Console/Site/SiteDeleteCommand.php (1)
101-176: Server-deletion flag and confirmation flow look correct; consider clarifying success messagingThe refactor from
removedFromServertodeletedFromServer, plus the updated “Deleting site from server...” and “Failed to delete site from server” messages, all align with the new terminology and the control flow around server vs inventory deletion looks sound:
$deletedFromServeris initialized once (line 105) and only flipped totrueon successful playbook execution (line 145).- When the server is missing, unreachable, or the playbook fails, the subsequent
if (!$deletedFromServer)branch (line 154) correctly gates whether to prompt “Remove site from inventory anyway?” before proceeding.- Early
return Command::FAILURE;when the user declines (line 165) avoids emitting a misleading success message.One small UX consideration: the final success message is now always
"Site '{$site->domain}' removed from inventory"(line 175), even when the server deletion succeeded. That’s accurate, but a bit opaque about whether the server was also cleaned up. If you want to make this clearer for operators, you could optionally differentiate the message when$deletedFromServer === true(e.g., "deleted from server and removed from inventory") while preserving the current behavior as the default.Overall, the logic is correct and consistent with the guidelines that Commands orchestrate rather than contain business logic.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
app/Console/Site/SiteDeleteCommand.php(5 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.php
📄 CodeRabbit inference engine (.cursor/rules/00-main.mdc)
**/*.php: Eliminate single-use methods: inline if called once
Cache computed values: initialize expensive calculations in constructor
Avoid method call overhead: direct property access when appropriate
Group related functions into comment-separated sections
Order alphabetically after grouping logically
**/*.php: Follow PSR-12 standard with strict types enabled and use PHP 8.x features (unions, match, attributes, readonly)
Use explicit return types with generics (e.g.,Collection<int, User>) for all functions and methods
Use dependency injection via Symfony patterns for all object dependencies
Use Symfony classes over native PHP functions (Filesystem, Process) for testability
Always use Yoda conditions: place constants/literals on the LEFT side of comparisons (e.g.,null === $value) to prevent accidental assignment
Always use braces for ALL control structures (if, else, elseif, for, foreach, while, do-while), even for single-line bodies
Use@varannotations to help PHPStan understand types it cannot infer, notassert()in production code
Always addusestatements for vendor packages and project classes; root namespace FQDNs acceptable for built-in exceptions (e.g.,\InvalidArgumentException)
Use$container->build(ClassName::class)for all object creation; use this except for DTOs, value objects, and pure data structures
Use constructor injection in production code and direct instantiation in tests for container access
All object dependencies must be declared in constructor signatures; NO circular dependencies allowed
Use minimalist DocBlock descriptions with parameters and return types for classes and functions; separate sections visually with one newline between headers/paragraphs
**/*.php: Services and Repositories must throw \RuntimeException with complete, actionable messages that include relevant context (paths, names, IDs, hosts) and are user-facing, not fragments
When catching and re-throwing exceptions in Services and Repositories, use t...
Files:
app/Console/Site/SiteDeleteCommand.php
**/*Command.php
📄 CodeRabbit inference engine (.cursor/rules/01-architecture.mdc)
Command Layer: handle user interaction and orchestrate Services; contain NO business logic, NO duplicate orchestration, NO invocation of other commands
**/*Command.php: Command layer (Commands and Orchestration Traits) must display caught \RuntimeException messages directly without adding redundant prefixes like 'Failed to...'
Only add contextual information to exception displays in Command layer when necessary: raw output for debugging, actionable troubleshooting steps, or when the exception message is too technical/generic
Files:
app/Console/Site/SiteDeleteCommand.php
**/{*Command,*Service}.php
📄 CodeRabbit inference engine (.cursor/rules/01-architecture.mdc)
Only Commands perform console I/O using SymfonyStyle; Services return exceptions/data for Commands to display
Files:
app/Console/Site/SiteDeleteCommand.php
🧬 Code graph analysis (1)
app/Console/Site/SiteDeleteCommand.php (1)
app/Contracts/BaseCommand.php (2)
warn(214-217)yay(206-209)
🔇 Additional comments (1)
app/Console/Site/SiteDeleteCommand.php (1)
17-20: Description wording is consistent with the new lifecycle terminologyThe updated command description reads clearly and matches the “delete from server / remove from inventory” flow used in the rest of the command and related site commands. No issues here.
Summary by CodeRabbit
New Features
Changes
✏️ Tip: You can customize this high-level summary in your review settings.