feat: provision DigitalOcean droplets - #59
Conversation
WalkthroughAdds DigitalOcean provisioning and related validation/helpers, extends ServerDTO with provider and dropletId, updates repository serialization, and refactors server console commands (add/list/delete) and helper traits for cloud-aware flows and improved key handling. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Cmd as ServerProvisionDOCmd
participant DO as DigitalOceanService
participant Repo as ServerRepository
participant IO as IOService
User->>Cmd: run command
Cmd->>DO: init API (credentials)
DO-->>Cmd: account data (keys, regions, sizes, images)
Cmd->>User: prompt for name/region/size/image/ssh-key/private-key-path/options
User-->>Cmd: provide inputs
Cmd->>Cmd: validate inputs (DigitalOceanValidationTrait)
Cmd->>IO: resolve private key path (KeyHelpersTrait)
alt resolution failure
IO-->>Cmd: null -> Cmd returns FAILURE
end
Cmd->>DO: create droplet (with ssh keys)
DO-->>Cmd: droplet id
Cmd->>DO: poll until active
alt droplet fails
Cmd->>DO: rollback destroy droplet
Cmd->>User: error + exit FAILURE
else droplet ready
DO-->>Cmd: droplet IP
Cmd->>Repo: persist ServerDTO(provider='digitalocean', dropletId)
Repo-->>Cmd: success
Cmd->>User: displayServerDeets + usage hint
end
sequenceDiagram
participant User
participant Cmd as ServerDeleteCmd
participant IO as IOService
participant DO as DigitalOceanService
participant Repo as ServerRepository
User->>Cmd: run delete (maybe --force)
Cmd->>Cmd: ensureServersAvailable()
Cmd->>User: selectServer prompt
User-->>Cmd: choose server
Cmd->>IO: displayServerDeets (includes droplet info if DO)
alt server is DigitalOcean (isDigitalOceanServer)
Cmd->>DO: init API
alt auth failure
DO-->>Cmd: error -> Cmd returns FAILURE
end
alt droplet exists
Cmd->>User: show droplet warning & require typed name (unless --force)
User-->>Cmd: confirm (typed match)
Cmd->>DO: destroy droplet (spinner)
alt destroy fails
Cmd->>User: offer inventory-only removal
end
end
end
Cmd->>Repo: remove server from inventory
Repo-->>Cmd: success -> Cmd displays success hint (force flag in redir data if used)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 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: 2
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (12)
app/Console/Server/ServerAddCommand.php(4 hunks)app/Console/Server/ServerDeleteCommand.php(5 hunks)app/Console/Server/ServerListCommand.php(2 hunks)app/Console/Server/ServerProvisionDigitalOceanCommand.php(1 hunks)app/DTOs/ServerDTO.php(1 hunks)app/Repositories/ServerRepository.php(2 hunks)app/SymfonyApp.php(2 hunks)app/Traits/DigitalOceanCommandTrait.php(1 hunks)app/Traits/DigitalOceanValidationTrait.php(1 hunks)app/Traits/KeyHelpersTrait.php(1 hunks)app/Traits/ServerHelpersTrait.php(2 hunks)app/Traits/ServerValidationTrait.php(1 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
**/*.php
📄 CodeRabbit inference engine (.cursor/rules/00-main.mdc)
**/*.php: Eliminate single-use methods: inline if a method is called only once
Cache computed values: initialize expensive calculations in the constructor
Avoid method call overhead: prefer direct property access when appropriate
**/*.php: Adhere to PSR-12, enable strict_types, and leverage PHP 8.x features (union types, match, attributes, readonly)
Use explicit return types, including generic-like annotations where applicable (e.g., Collection<int, User>)
Prefer Symfony components (e.g., Filesystem, Process) over native PHP functions for testability
Always import classes via use statements; only use root FQDNs for core exceptions (e.g., \InvalidArgumentException, \RuntimeException). Do not use inline FQDNs for non-root namespaces
Create objects via $container->build(ClassName::class) everywhere except DTOs, value objects, and pure data structures
Use minimalist DocBlocks documenting description, parameters, and return types for classes and functions
Follow the specified comment structure with section headers/subheaders and spacing; remove obsolete comments with removed code
Files:
app/DTOs/ServerDTO.phpapp/Console/Server/ServerAddCommand.phpapp/Traits/KeyHelpersTrait.phpapp/Traits/ServerHelpersTrait.phpapp/Repositories/ServerRepository.phpapp/Traits/ServerValidationTrait.phpapp/Console/Server/ServerProvisionDigitalOceanCommand.phpapp/Traits/DigitalOceanValidationTrait.phpapp/Traits/DigitalOceanCommandTrait.phpapp/SymfonyApp.phpapp/Console/Server/ServerDeleteCommand.phpapp/Console/Server/ServerListCommand.php
**/*Command.php
📄 CodeRabbit inference engine (.cursor/rules/01-architecture.mdc)
**/*Command.php: Commands handle user interaction (I/O), orchestration, styling, error formatting, and prompts using SymfonyStyle
Commands must not contain business logic; delegate to Services
Commands must not invoke other commands (no proxy commands)
Files:
app/Console/Server/ServerAddCommand.phpapp/Console/Server/ServerProvisionDigitalOceanCommand.phpapp/Console/Server/ServerDeleteCommand.phpapp/Console/Server/ServerListCommand.php
**/*{Command,Service}.php
📄 CodeRabbit inference engine (.cursor/rules/01-architecture.mdc)
All dependencies should be expressed in constructor signatures; avoid circular dependencies
Files:
app/Console/Server/ServerAddCommand.phpapp/Console/Server/ServerProvisionDigitalOceanCommand.phpapp/Console/Server/ServerDeleteCommand.phpapp/Console/Server/ServerListCommand.php
**/*ValidationTrait.php
📄 CodeRabbit inference engine (.cursor/rules/03-commands.mdc)
**/*ValidationTrait.php: Validation methods for prompts/options must accept mixed and return ?string error or null (do not throw exceptions).
Naming: use validateInput() for prompt/option validators returning ?string; use validate() to throw exceptions for heavy I/O validations.
Files:
app/Traits/ServerValidationTrait.phpapp/Traits/DigitalOceanValidationTrait.php
**/SymfonyApp.php
📄 CodeRabbit inference engine (.cursor/rules/01-architecture.mdc)
Register console commands in SymfonyApp.php
Files:
app/SymfonyApp.php
🧠 Learnings (13)
📚 Learning: 2025-10-24T20:01:06.209Z
Learnt from: CR
PR: bigpixelrocket/deployer-php#0
File: .cursor/rules/03-commands.mdc:0-0
Timestamp: 2025-10-24T20:01:06.209Z
Learning: Applies to src/Command/**/*Command.php : Option naming: --server/--site select existing resources; --name defines a new resource property; follow the provided table for common options.
Applied to files:
app/Console/Server/ServerAddCommand.phpapp/Traits/ServerHelpersTrait.phpapp/SymfonyApp.phpapp/Console/Server/ServerDeleteCommand.phpapp/Console/Server/ServerListCommand.php
📚 Learning: 2025-10-24T19:59:22.863Z
Learnt from: CR
PR: bigpixelrocket/deployer-php#0
File: .cursor/rules/01-architecture.mdc:0-0
Timestamp: 2025-10-24T19:59:22.863Z
Learning: Applies to **/*Command.php : Commands handle user interaction (I/O), orchestration, styling, error formatting, and prompts using SymfonyStyle
Applied to files:
app/Console/Server/ServerAddCommand.phpapp/SymfonyApp.php
📚 Learning: 2025-10-24T20:01:06.209Z
Learnt from: CR
PR: bigpixelrocket/deployer-php#0
File: .cursor/rules/03-commands.mdc:0-0
Timestamp: 2025-10-24T20:01:06.209Z
Learning: Applies to **/BaseCommand.php : BaseCommand handles shared initialization/configuration/orchestration only; do not implement individual I/O operations here.
Applied to files:
app/Console/Server/ServerAddCommand.php
📚 Learning: 2025-10-24T19:59:22.863Z
Learnt from: CR
PR: bigpixelrocket/deployer-php#0
File: .cursor/rules/01-architecture.mdc:0-0
Timestamp: 2025-10-24T19:59:22.863Z
Learning: Applies to **/SymfonyApp.php : Register console commands in SymfonyApp.php
Applied to files:
app/Console/Server/ServerAddCommand.phpapp/SymfonyApp.php
📚 Learning: 2025-10-24T20:01:06.209Z
Learnt from: CR
PR: bigpixelrocket/deployer-php#0
File: .cursor/rules/03-commands.mdc:0-0
Timestamp: 2025-10-24T20:01:06.209Z
Learning: Applies to **/ConsoleOutputTrait.php : Keep output/formatting methods in ConsoleOutputTrait and implement them using $this->io (SymfonyStyle).
Applied to files:
app/Traits/KeyHelpersTrait.php
📚 Learning: 2025-10-24T20:01:06.209Z
Learnt from: CR
PR: bigpixelrocket/deployer-php#0
File: .cursor/rules/03-commands.mdc:0-0
Timestamp: 2025-10-24T20:01:06.209Z
Learning: Applies to **/BaseCommand.php : If an IO helper is missing, add it to BaseCommand with modern styling instead of using Symfony IO directly.
Applied to files:
app/Traits/KeyHelpersTrait.php
📚 Learning: 2025-10-24T20:01:06.209Z
Learnt from: CR
PR: bigpixelrocket/deployer-php#0
File: .cursor/rules/03-commands.mdc:0-0
Timestamp: 2025-10-24T20:01:06.209Z
Learning: Applies to **/*ValidationTrait.php : Naming: use validate*Input() for prompt/option validators returning ?string; use validate*() to throw exceptions for heavy I/O validations.
Applied to files:
app/Traits/DigitalOceanValidationTrait.php
📚 Learning: 2025-10-24T20:01:06.210Z
Learnt from: CR
PR: bigpixelrocket/deployer-php#0
File: .cursor/rules/03-commands.mdc:0-0
Timestamp: 2025-10-24T20:01:06.210Z
Learning: Test validation traits via small wrapper methods that expose validate*Input() and assert null or error strings accordingly.
Applied to files:
app/Traits/DigitalOceanValidationTrait.php
📚 Learning: 2025-10-24T19:59:22.863Z
Learnt from: CR
PR: bigpixelrocket/deployer-php#0
File: .cursor/rules/01-architecture.mdc:0-0
Timestamp: 2025-10-24T19:59:22.863Z
Learning: Applies to **/*Command.php : Commands must not contain business logic; delegate to Services
Applied to files:
app/SymfonyApp.php
📚 Learning: 2025-10-24T20:01:06.209Z
Learnt from: CR
PR: bigpixelrocket/deployer-php#0
File: .cursor/rules/03-commands.mdc:0-0
Timestamp: 2025-10-24T20:01:06.209Z
Learning: Applies to src/Command/**/*Command.php : Use only OPTIONS (no positional arguments) to enable getOptionOrPrompt across the board.
Applied to files:
app/Console/Server/ServerDeleteCommand.php
📚 Learning: 2025-10-24T20:01:06.209Z
Learnt from: CR
PR: bigpixelrocket/deployer-php#0
File: .cursor/rules/03-commands.mdc:0-0
Timestamp: 2025-10-24T20:01:06.209Z
Learning: Applies to src/Command/**/*Command.php : Pair all options with getOptionOrPrompt to support both non-interactive and interactive usage.
Applied to files:
app/Console/Server/ServerDeleteCommand.php
📚 Learning: 2025-10-24T20:01:06.210Z
Learnt from: CR
PR: bigpixelrocket/deployer-php#0
File: .cursor/rules/03-commands.mdc:0-0
Timestamp: 2025-10-24T20:01:06.210Z
Learning: Applies to src/Command/**/*Command.php : Boolean flags must use VALUE_NONE; data inputs must use VALUE_REQUIRED; only --yes has a short flag (-y).
Applied to files:
app/Console/Server/ServerDeleteCommand.php
📚 Learning: 2025-10-24T20:01:06.209Z
Learnt from: CR
PR: bigpixelrocket/deployer-php#0
File: .cursor/rules/03-commands.mdc:0-0
Timestamp: 2025-10-24T20:01:06.209Z
Learning: Applies to src/Command/**/*Command.php : Support both interactive prompts and CLI options by using getOptionOrPrompt for each option (define options in configure; resolve via getOptionOrPrompt in execute).
Applied to files:
app/Console/Server/ServerDeleteCommand.php
🧬 Code graph analysis (7)
app/Console/Server/ServerAddCommand.php (2)
app/Traits/KeyHelpersTrait.php (1)
resolvePrivateKeyPath(46-52)app/Services/IOService.php (1)
error(498-501)
app/Traits/ServerHelpersTrait.php (3)
app/Services/IOService.php (3)
IOService(30-583)warning(490-493)writeln(463-469)app/Repositories/ServerRepository.php (1)
all(104-114)app/DTOs/ServerDTO.php (1)
ServerDTO(7-19)
app/Repositories/ServerRepository.php (1)
app/DTOs/ServerDTO.php (1)
ServerDTO(7-19)
app/Traits/ServerValidationTrait.php (1)
app/Repositories/ServerRepository.php (1)
ServerRepository(15-195)
app/Console/Server/ServerProvisionDigitalOceanCommand.php (11)
app/Contracts/BaseCommand.php (1)
BaseCommand(29-158)app/DTOs/ServerDTO.php (1)
ServerDTO(7-19)app/Services/IOService.php (13)
hr(517-523)h1(506-512)promptSpin(439-452)warning(490-493)writeln(463-469)getValidatedOptionOrPrompt(159-182)promptText(200-218)promptSelect(304-322)getOptionOrPrompt(84-132)error(498-501)promptConfirm(260-276)success(482-485)showCommandHint(530-566)app/Traits/DigitalOceanCommandTrait.php (1)
initializeDigitalOceanAPI(33-66)app/Services/DigitalOcean/DigitalOceanAccountService.php (5)
getUserSshKeys(149-167)getAvailableRegions(27-47)getAvailableSizes(54-79)getAvailableImages(86-116)getUserVpcs(123-142)app/Traits/ServerValidationTrait.php (1)
validateNameInput(23-41)app/Traits/DigitalOceanValidationTrait.php (5)
validateRegionInput(19-35)validateSizeInput(44-60)validateImageInput(69-85)validateSshKeyInput(119-134)validateVpcUuidInput(92-110)app/Traits/KeyHelpersTrait.php (1)
resolvePrivateKeyPath(46-52)app/Services/DigitalOcean/DigitalOceanDropletService.php (3)
createDroplet(33-75)waitForDropletReady(107-129)getDropletIp(136-157)app/Repositories/ServerRepository.php (1)
create(48-65)app/Traits/ServerHelpersTrait.php (1)
displayServerDeets(95-113)
app/Console/Server/ServerDeleteCommand.php (4)
app/Traits/ServerHelpersTrait.php (3)
selectServer(53-88)displayServerDeets(95-113)isDigitalOceanServer(118-121)app/Services/IOService.php (9)
hr(517-523)error(498-501)writeln(463-469)warning(490-493)promptText(200-218)getOptionOrPrompt(84-132)promptConfirm(260-276)promptSpin(439-452)success(482-485)app/Traits/DigitalOceanCommandTrait.php (1)
initializeDigitalOceanAPI(33-66)app/Services/DigitalOcean/DigitalOceanDropletService.php (1)
destroyDroplet(168-185)
app/Console/Server/ServerListCommand.php (3)
app/Services/IOService.php (1)
h1(506-512)app/Traits/ServerHelpersTrait.php (2)
ensureServersAvailable(27-46)displayServerDeets(95-113)app/Repositories/SiteRepository.php (1)
findByServer(111-124)
🪛 GitHub Actions: Rector
app/Traits/DigitalOceanValidationTrait.php
[error] 150-150: Rector dry-run would modify code: use 'trim' as a function (FunctionFirstClassCallableRector) in line 150. Suggested change present in diff.
Automatically destroy droplets when provisioning fails after creation. Handles failures during IP retrieval and inventory addition by cleaning up the created droplet to prevent orphaned resources.
Replace string callables with first-class callable syntax for PHP 8.1+ compatibility and improved type safety.
Add blank lines after error messages for better visual separation and remove decorative comment separators.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (5)
app/Console/Server/ServerAddCommand.php (2)
131-136: Enhance error message with actionable guidance.The error message doesn't inform users which paths were checked or how to resolve the issue. Consider providing more context about the attempted paths and next steps.
Apply this diff to provide a more helpful error message:
if ($privateKeyPath === null) { - $this->io->error('SSH private key not found.'); + $this->io->error('SSH private key not found. Checked: ' . ($privateKeyPathRaw ?: '~/.ssh/id_ed25519, ~/.ssh/id_rsa')); $this->io->writeln('');Alternatively, for a more detailed message:
if ($privateKeyPath === null) { - $this->io->error('SSH private key not found.'); + if ($privateKeyPathRaw !== '') { + $this->io->error("SSH private key not found at: {$privateKeyPathRaw}"); + } else { + $this->io->error('SSH private key not found. Please ensure ~/.ssh/id_ed25519 or ~/.ssh/id_rsa exists, or specify a custom path.'); + } $this->io->writeln('');
117-126: Consider simplifying the prompt label.The label on line 121 is quite long. Consider moving the default path information to the hint for better readability.
Apply this diff to improve prompt clarity:
$privateKeyPathRaw = $this->io->getOptionOrPrompt( 'private-key-path', fn (): string => $this->io->promptText( - label: 'Path to SSH private key (leave empty for default ~/.ssh/id_ed25519 or ~/.ssh/id_rsa):', + label: 'Path to SSH private key:', default: '', required: false, - hint: 'Used to connect to the server' + hint: 'Leave empty to use ~/.ssh/id_ed25519 or ~/.ssh/id_rsa' ) );app/Console/Server/ServerProvisionDigitalOceanCommand.php (3)
73-93: Wrap account data retrieval in try-catch for better error handling.If any of the account service methods (
getUserSshKeys,getAvailableRegions, etc.) throw a\RuntimeException, it will bubble up as an uncaught exception, resulting in poor UX. Consider wrapping the retrieval and the empty keys check in a try-catch block to provide formatted error messages, similar to how API initialization is handled at lines 66-68.Apply this diff to add error handling:
+ try { $accountData = $this->io->promptSpin( fn () => [ 'keys' => $this->digitalOcean->account->getUserSshKeys(), 'regions' => $this->digitalOcean->account->getAvailableRegions(), 'sizes' => $this->digitalOcean->account->getAvailableSizes(), 'images' => $this->digitalOcean->account->getAvailableImages(), ], 'Retrieving account information...' ); if (count($accountData['keys']) === 0) { $this->io->warning('No SSH keys found in your DigitalOcean account'); $this->io->writeln([ '', 'You must add at least one SSH key before provisioning a server.', 'Run <fg=cyan>key:add:digitalocean</> to add an SSH key.', '', ]); return Command::FAILURE; } + } catch (\RuntimeException $e) { + $this->io->error('Failed to retrieve account information: ' . $e->getMessage()); + $this->io->writeln(''); + + return Command::FAILURE; + }
309-309: Optional: Consider if blank line is necessary.This blank line adds spacing before the "Waiting for droplet..." message. While it improves readability, it's optional and could be removed if you prefer more compact output.
409-411: Provide more context in rollback error message.The catch block outputs just the error message without context. Users would benefit from knowing that this error occurred specifically during cleanup/rollback of the droplet.
Apply this diff to add context:
} catch (\Throwable $cleanupError) { - $this->io->warning($cleanupError->getMessage()); + $this->io->warning('Could not destroy droplet during rollback: ' . $cleanupError->getMessage()); }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
app/Console/Server/ServerAddCommand.php(4 hunks)app/Console/Server/ServerProvisionDigitalOceanCommand.php(1 hunks)app/Repositories/SiteRepository.php(1 hunks)app/Traits/DigitalOceanValidationTrait.php(1 hunks)app/Traits/SiteHelpersTrait.php(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- app/Traits/DigitalOceanValidationTrait.php
🧰 Additional context used
📓 Path-based instructions (3)
**/*.php
📄 CodeRabbit inference engine (.cursor/rules/00-main.mdc)
**/*.php: Eliminate single-use methods: inline if a method is called only once
Cache computed values: initialize expensive calculations in the constructor
Avoid method call overhead: prefer direct property access when appropriate
**/*.php: Adhere to PSR-12, enable strict_types, and leverage PHP 8.x features (union types, match, attributes, readonly)
Use explicit return types, including generic-like annotations where applicable (e.g., Collection<int, User>)
Prefer Symfony components (e.g., Filesystem, Process) over native PHP functions for testability
Always import classes via use statements; only use root FQDNs for core exceptions (e.g., \InvalidArgumentException, \RuntimeException). Do not use inline FQDNs for non-root namespaces
Create objects via $container->build(ClassName::class) everywhere except DTOs, value objects, and pure data structures
Use minimalist DocBlocks documenting description, parameters, and return types for classes and functions
Follow the specified comment structure with section headers/subheaders and spacing; remove obsolete comments with removed code
Files:
app/Console/Server/ServerAddCommand.phpapp/Console/Server/ServerProvisionDigitalOceanCommand.phpapp/Repositories/SiteRepository.phpapp/Traits/SiteHelpersTrait.php
**/*Command.php
📄 CodeRabbit inference engine (.cursor/rules/01-architecture.mdc)
**/*Command.php: Commands handle user interaction (I/O), orchestration, styling, error formatting, and prompts using SymfonyStyle
Commands must not contain business logic; delegate to Services
Commands must not invoke other commands (no proxy commands)
Files:
app/Console/Server/ServerAddCommand.phpapp/Console/Server/ServerProvisionDigitalOceanCommand.php
**/*{Command,Service}.php
📄 CodeRabbit inference engine (.cursor/rules/01-architecture.mdc)
All dependencies should be expressed in constructor signatures; avoid circular dependencies
Files:
app/Console/Server/ServerAddCommand.phpapp/Console/Server/ServerProvisionDigitalOceanCommand.php
🧠 Learnings (4)
📚 Learning: 2025-10-24T20:01:06.209Z
Learnt from: CR
PR: bigpixelrocket/deployer-php#0
File: .cursor/rules/03-commands.mdc:0-0
Timestamp: 2025-10-24T20:01:06.209Z
Learning: Applies to src/Command/**/*Command.php : Option naming: --server/--site select existing resources; --name defines a new resource property; follow the provided table for common options.
Applied to files:
app/Console/Server/ServerAddCommand.php
📚 Learning: 2025-10-24T19:59:22.863Z
Learnt from: CR
PR: bigpixelrocket/deployer-php#0
File: .cursor/rules/01-architecture.mdc:0-0
Timestamp: 2025-10-24T19:59:22.863Z
Learning: Applies to **/*Command.php : Commands handle user interaction (I/O), orchestration, styling, error formatting, and prompts using SymfonyStyle
Applied to files:
app/Console/Server/ServerAddCommand.php
📚 Learning: 2025-10-24T20:01:06.209Z
Learnt from: CR
PR: bigpixelrocket/deployer-php#0
File: .cursor/rules/03-commands.mdc:0-0
Timestamp: 2025-10-24T20:01:06.209Z
Learning: Applies to **/BaseCommand.php : BaseCommand handles shared initialization/configuration/orchestration only; do not implement individual I/O operations here.
Applied to files:
app/Console/Server/ServerAddCommand.php
📚 Learning: 2025-10-24T19:59:22.863Z
Learnt from: CR
PR: bigpixelrocket/deployer-php#0
File: .cursor/rules/01-architecture.mdc:0-0
Timestamp: 2025-10-24T19:59:22.863Z
Learning: Applies to **/SymfonyApp.php : Register console commands in SymfonyApp.php
Applied to files:
app/Console/Server/ServerAddCommand.php
🧬 Code graph analysis (2)
app/Console/Server/ServerAddCommand.php (3)
app/Traits/KeyHelpersTrait.php (2)
resolvePrivateKeyPath(46-52)KeyHelpersTrait(19-137)app/Services/IOService.php (2)
error(498-501)writeln(463-469)app/Traits/KeyValidationTrait.php (1)
KeyValidationTrait(16-116)
app/Console/Server/ServerProvisionDigitalOceanCommand.php (10)
app/Contracts/BaseCommand.php (1)
BaseCommand(29-158)app/DTOs/ServerDTO.php (1)
ServerDTO(7-19)app/Services/IOService.php (13)
hr(517-523)h1(506-512)promptSpin(439-452)warning(490-493)writeln(463-469)getValidatedOptionOrPrompt(159-182)promptText(200-218)promptSelect(304-322)getOptionOrPrompt(84-132)error(498-501)promptConfirm(260-276)success(482-485)showCommandHint(530-566)app/Traits/DigitalOceanCommandTrait.php (1)
initializeDigitalOceanAPI(33-66)app/Services/DigitalOcean/DigitalOceanAccountService.php (5)
getUserSshKeys(149-167)getAvailableRegions(27-47)getAvailableSizes(54-79)getAvailableImages(86-116)getUserVpcs(123-142)app/Traits/ServerValidationTrait.php (1)
validateNameInput(23-41)app/Traits/DigitalOceanValidationTrait.php (5)
validateRegionInput(19-35)validateSizeInput(44-60)validateImageInput(69-85)validateSshKeyInput(119-134)validateVpcUuidInput(92-110)app/Traits/KeyHelpersTrait.php (1)
resolvePrivateKeyPath(46-52)app/Services/DigitalOcean/DigitalOceanDropletService.php (4)
createDroplet(33-75)waitForDropletReady(107-129)getDropletIp(136-157)destroyDroplet(168-185)app/Traits/ServerHelpersTrait.php (1)
displayServerDeets(95-113)
🔇 Additional comments (4)
app/Repositories/SiteRepository.php (1)
205-205: LGTM! Good modernization using first-class callable syntax.The change from
'is_string'tois_string(...)adopts PHP 8.1's first-class callable syntax, which aligns with the coding guideline to leverage PHP 8.x features. This is a syntax modernization with no behavioral change—the filtering logic remains identical.As per coding guidelines.
app/Traits/SiteHelpersTrait.php (1)
107-107: LGTM! Excellent modernization to first-class callables.The changes from string-based callable references (
'trim','strval') to first-class callable syntax (trim(...),strval(...)) are functionally equivalent and leverage PHP 8.1+ features as required by the coding guidelines. This approach is more explicit, type-safe, and provides better IDE support.As per coding guidelines.
Also applies to: 121-121
app/Console/Server/ServerAddCommand.php (2)
9-10: LGTM: Trait integration follows best practices.The KeyHelpersTrait and KeyValidationTrait are properly imported and integrated, providing key resolution and validation capabilities that align with the broader DigitalOcean provisioning feature introduced in this PR.
Also applies to: 22-23
39-40: LGTM: Logical option ordering.Placing private-key-path before username is reasonable since the key path requires resolution logic while username has a simple default value.
Summary by CodeRabbit
New Features
Improvements
Bug Fixes