feat: add site commands - #46
Conversation
Add SiteAddCommand, SiteDeleteCommand, and SiteListCommand with comprehensive site management functionality. Includes SiteHelpersTrait and SiteValidationTrait for reusable site operations and validation logic. Commands follow the established Server command patterns for consistency and maintainability.
Update SiteDTO with improved type hints and properties. Enhance SiteRepository with additional query and persistence methods to support the new site management command functionality.
Register new Site commands in SymfonyApp. Update TestConsoleCommand fixture to support site command testing patterns.
Align ServerAddCommand, ServerDeleteCommand, and ServerListCommand with improved patterns and consistency standards used across the codebase.
Add full integration and unit test coverage for Site commands: - SiteAddCommandTest, SiteDeleteCommandTest, SiteListCommandTest - SiteDTOTest, SiteRepositoryTest updates - SiteHelpersTraitTest, SiteValidationTraitTest
Update ServerAddCommandTest, ServerDeleteCommandTest, and ServerListCommandTest to align with new testing patterns and standards.
- Extracts git detection logic into reusable service layer - Provides detectRemoteUrl() and detectCurrentBranch() methods - Supports custom working directory parameter - Includes comprehensive unit tests with 7 test cases - Follows architecture rules for business logic separation
- Add GitService to BaseCommand constructor (alphabetically ordered) - Update mockCommandContainer() to bind GitService - Add mockGitService() test helper function - Update TestConsoleCommand to include GitService parameter - Add selectServers() and selectSite() to test methods - Add --servers option to test command configuration
- Replace private git detection methods with GitService calls - Add early server existence validation for CLI options - Wrap selectServers() in try-catch for error handling - Reduces command-layer business logic per architecture rules - Improves user experience with immediate validation feedback
- Validate CLI-provided server names immediately during parsing - Throw descriptive RuntimeException for non-existent servers - Add unit tests for successful and failed validations - Provides early feedback for CLI option errors - Interactive prompts already validated via UI constraints
- Merge single/multiple site tests into dataset-driven test - Reduce redundant assertions and test overlap - Decrease file size from 133 to 106 lines - Improve test-to-code ratio from 2.38x to 1.89x - Maintains comprehensive coverage with 5 test scenarios
Add validateRepoInput() method to SiteValidationTrait to validate git repository URL format before prompting. Validates that URLs start with git@, https://, http://, or ssh://. Update SiteAddCommand to use getValidatedOptionOrPrompt() instead of getOptionOrPrompt() for repository input, providing real-time validation as users type and preventing invalid URLs from being accepted.
Add comprehensive test coverage for validateRepoInput() method using dataset-driven testing. Tests cover valid URLs (HTTPS, HTTP, SSH formats), invalid formats (missing protocol, wrong protocol, paths), empty/whitespace input, and type validation.
Add blank line after validation error messages in getValidatedOptionOrPrompt() to improve visual separation between error output and subsequent prompts, enhancing readability in interactive CLI workflows.
WalkthroughAdds site management CLI (site:add/site:delete/site:list), Site DTO and repository changes (nullable repo/branch, isLocal, findByServer), a GitService, site helper/validation traits, updates server commands to be site-aware, injects GitService into BaseCommand, updates tests/fixtures, and adds a .gitignore entry. Changes
Sequence Diagram(s)sequenceDiagram
participant U as User
participant Cmd as SiteAddCommand
participant IO as IOService
participant Val as SiteValidationTrait
participant Git as GitService
participant Repo as SiteRepository
U->>Cmd: run site:add
Cmd->>Repo: ensure servers exist
alt no servers
Cmd->>IO: show error & guidance
Cmd-->>U: exit failure
else servers exist
Cmd->>IO: prompt domain/type/repo/branch/servers
IO-->>U: prompts
U-->>IO: provide inputs
IO->>Val: validate inputs
Val->>Repo: findByDomain (duplicate check)
alt type == git
Cmd->>Git: detectRemoteUrl / detectCurrentBranch
Git-->>Cmd: values or null
end
Cmd->>Val: validateServers(selected)
Cmd->>Repo: create(SiteDTO)
Repo-->>Cmd: success
Cmd->>IO: show success & hint
Cmd-->>U: exit success
end
sequenceDiagram
participant U as User
participant Cmd as ServerDeleteCommand
participant RepoS as ServerRepository
participant RepoSite as SiteRepository
participant IO as IOService
U->>Cmd: run server:delete --server NAME
Cmd->>RepoSite: findByServer(NAME)
alt sites exist
RepoSite-->>Cmd: list of sites
Cmd->>IO: show error + list
Cmd-->>U: exit failure
else no sites
Cmd->>IO: confirm deletion
alt confirmed
Cmd->>RepoS: delete(NAME)
RepoS-->>Cmd: success
Cmd->>IO: show success
else
Cmd->>IO: show cancelled
end
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60–90 minutes Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (8)
tests/Unit/Services/GitServiceTest.php (1)
13-26: Consider making environment-dependent tests more deterministic.The conditional assertions at Lines 21-25 and 68-72 check type when non-null but don't validate meaningful behavior. Since these tests depend on whether the test runs in a git repository, consider:
- Setting up a temporary git repository in the test for deterministic success cases
- Or documenting that these tests validate "no crashes" behavior in any environment
As-is, the tests provide basic coverage but could be strengthened.
Also applies to: 60-73
tests/Integration/Console/Site/SiteAddCommandTest.php (1)
16-36: Consider using SiteDTO objects for consistency.The test helper accepts
ServerDTOobjects for$existingServersbut raw arrays for$existingSites. While this works, it creates an inconsistency withtests/Integration/Console/Site/SiteListCommandTest.php(lines 16-37), which acceptsSiteDTOobjects and maps them to arrays.For consistency across the test suite, consider standardizing on one approach. The simpler pattern (accepting raw arrays, as done here) is more direct and requires less ceremony.
If you choose to standardize on raw arrays (recommended for simplicity), update
SiteListCommandTestto match this pattern. If you prefer the DTO approach, update this helper and others to acceptSiteDTOobjects.tests/Integration/Console/Site/SiteListCommandTest.php (1)
16-37: Simplify by accepting raw arrays directly.The test helper accepts
SiteDTOobjects (line 19's type hint) and immediately maps them to raw arrays (lines 23-31). This adds unnecessary ceremony compared to the pattern used in other site command tests.Consider accepting raw arrays directly, matching the pattern in
SiteAddCommandTestandSiteDeleteCommandTest:-/** - * @param array<int, SiteDTO> $existingSites - */ -function createSiteListCommandTester(array $existingSites = []): CommandTester +function createSiteListCommandTester(array $existingSites = []): CommandTester { // Build inventory data with sites $inventoryData = [ - 'sites' => array_map( - fn (SiteDTO $site) => [ - 'domain' => $site->domain, - 'repo' => $site->repo, - 'branch' => $site->branch, - 'servers' => $site->servers, - ], - $existingSites - ), + 'sites' => $existingSites, ];Then update the test data at lines 50-53 to provide raw arrays instead of constructing and deconstructing SiteDTOs.
app/DTOs/SiteDTO.php (1)
15-16: Clarify servers doc: they are server names, not hostnames/addressesRepository methods treat servers as names (e.g., 'web1'), not hostnames/IPs. Update the doc to avoid confusion.
- * @param array<int, string> $servers Ordered list of server hostnames or addresses associated with the site. + * @param array<int, string> $servers Ordered list of server names associated with the site (as defined in inventory).app/Services/GitService.php (1)
42-49: Minor robustness: treat empty output as null and catch ThrowableAvoid returning empty strings and catch all throwables.
- if ($process->isSuccessful()) { - return trim($process->getOutput()); - } + if ($process->isSuccessful()) { + $out = trim($process->getOutput()); + return $out !== '' ? $out : null; + } @@ - } catch (\Exception) { + } catch (\Throwable) { return null; }Also applies to: 72-79
app/Console/Site/SiteDeleteCommand.php (2)
51-56: Show command hint on early SUCCESS when no site selectedGuideline: always call showCommandHint() before returning SUCCESS. If selectSite() returns SUCCESS (e.g., no sites), display the hint.
- if ($selection['site'] === null) { - return $selection['exit_code']; - } + if ($selection['site'] === null) { + if ($selection['exit_code'] === Command::SUCCESS) { + $this->io->showCommandHint('site:delete', [ + 'site' => $input->getOption('site'), + 'yes' => (bool) $input->getOption('yes'), + ]); + } + return $selection['exit_code']; + }As per coding guidelines.
74-79: Show command hint when user cancels (SUCCESS path)Cancellation returns SUCCESS; include the non-interactive hint for consistency.
- if (!$confirmed) { - $this->io->warning('Cancelled deleting site'); - $this->io->writeln(''); - - return Command::SUCCESS; - } + if (!$confirmed) { + $this->io->warning('Cancelled deleting site'); + $this->io->writeln(''); + $this->io->showCommandHint('site:delete', [ + 'site' => $input->getOption('site'), + 'yes' => (bool) $input->getOption('yes'), + ]); + return Command::SUCCESS; + }As per coding guidelines.
app/Traits/SiteValidationTrait.php (1)
63-90: Prefer array_reduce or in_array for prefix checking.Consider simplifying the prefix validation logic for improved readability.
Apply this diff:
- // Basic format check - should start with git@, https://, http://, or ssh:// $repo = trim($repo); $validPrefixes = ['git@', 'https://', 'http://', 'ssh://']; - $hasValidPrefix = false; - - foreach ($validPrefixes as $prefix) { - if (str_starts_with($repo, $prefix)) { - $hasValidPrefix = true; - break; - } - } + + // Basic format check - should start with git@, https://, http://, or ssh:// + $hasValidPrefix = false; + foreach ($validPrefixes as $prefix) { + if (str_starts_with($repo, $prefix)) { + $hasValidPrefix = true; + break; + } + } if (!$hasValidPrefix) {Alternatively, use a more functional approach:
- // Basic format check - should start with git@, https://, http://, or ssh:// $repo = trim($repo); $validPrefixes = ['git@', 'https://', 'http://', 'ssh://']; - $hasValidPrefix = false; - - foreach ($validPrefixes as $prefix) { - if (str_starts_with($repo, $prefix)) { - $hasValidPrefix = true; - break; - } - } + + // Basic format check - should start with git@, https://, http://, or ssh:// + $hasValidPrefix = array_reduce( + $validPrefixes, + fn($carry, $prefix) => $carry || str_starts_with($repo, $prefix), + false + ); if (!$hasValidPrefix) {
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (28)
.gitignore(1 hunks)app/Console/Server/ServerAddCommand.php(2 hunks)app/Console/Server/ServerDeleteCommand.php(1 hunks)app/Console/Server/ServerListCommand.php(3 hunks)app/Console/Site/SiteAddCommand.php(1 hunks)app/Console/Site/SiteDeleteCommand.php(1 hunks)app/Console/Site/SiteListCommand.php(1 hunks)app/Contracts/BaseCommand.php(2 hunks)app/DTOs/SiteDTO.php(1 hunks)app/Repositories/SiteRepository.php(2 hunks)app/Services/GitService.php(1 hunks)app/Services/IOService.php(1 hunks)app/SymfonyApp.php(2 hunks)app/Traits/SiteHelpersTrait.php(1 hunks)app/Traits/SiteValidationTrait.php(1 hunks)tests/Fixtures/TestConsoleCommand.php(6 hunks)tests/Integration/Console/Server/ServerAddCommandTest.php(7 hunks)tests/Integration/Console/Server/ServerDeleteCommandTest.php(2 hunks)tests/Integration/Console/Server/ServerListCommandTest.php(5 hunks)tests/Integration/Console/Site/SiteAddCommandTest.php(1 hunks)tests/Integration/Console/Site/SiteDeleteCommandTest.php(1 hunks)tests/Integration/Console/Site/SiteListCommandTest.php(1 hunks)tests/TestHelpers.php(5 hunks)tests/Unit/DTOs/SiteDTOTest.php(2 hunks)tests/Unit/Repositories/SiteRepositoryTest.php(4 hunks)tests/Unit/Services/GitServiceTest.php(1 hunks)tests/Unit/Traits/SiteHelpersTraitTest.php(1 hunks)tests/Unit/Traits/SiteValidationTraitTest.php(1 hunks)
🧰 Additional context used
📓 Path-based instructions (11)
**/*.php
📄 CodeRabbit inference engine (.cursor/rules/00-main.mdc)
**/*.php: Eliminate single-use private methods by inlining them directly
Cache expensive computed values by initializing them in the constructor instead of recomputing
Prefer direct property access over method calls when appropriate to avoid call overhead
Organize code into comment-separated sections; prefer alphabetical ordering when it does not conflict with logical grouping
**/*.php: Adhere to PSR-12 coding style in all PHP files
Declare strict_types=1 at the top of every PHP file
Prefer PHP 8.x features (union types, match, attributes, readonly) where appropriate
Always import classes with use statements; avoid fully qualified class names in code bodies
All methods must declare explicit return types; use proper generics in types/docblocks (e.g., Collection<int, User>)
Use dependency injection instead of manually resolving or instantiating classes
Prefer Symfony component classes (e.g., Filesystem, Process) over native PHP functions for testability
All object creation must use $container->build(ClassName::class) instead of new, except for value objects/DTOs/pure data structures
In production code, access the Container via constructor injection, not via static/global access
Add minimal DocBlock comments with descriptions, parameters, and return types for classes and functions
Use comments as visual separators for sections/subsections with a single newline between header, subheader, and paragraph; avoid obvious or stale comments
Run rector on changed PHP files before completing a task
Run pint on changed PHP files to fix code style before completing a task
Files:
app/Console/Server/ServerDeleteCommand.phpapp/Services/GitService.phpapp/DTOs/SiteDTO.phpapp/Services/IOService.phptests/TestHelpers.phpapp/Console/Server/ServerAddCommand.phpapp/Repositories/SiteRepository.phptests/Integration/Console/Server/ServerDeleteCommandTest.phptests/Integration/Console/Site/SiteDeleteCommandTest.phpapp/Console/Server/ServerListCommand.phptests/Unit/DTOs/SiteDTOTest.phpapp/Contracts/BaseCommand.phpapp/Traits/SiteValidationTrait.phptests/Unit/Traits/SiteValidationTraitTest.phptests/Unit/Services/GitServiceTest.phptests/Integration/Console/Server/ServerListCommandTest.phpapp/Traits/SiteHelpersTrait.phptests/Fixtures/TestConsoleCommand.phptests/Integration/Console/Site/SiteAddCommandTest.phptests/Integration/Console/Server/ServerAddCommandTest.phpapp/Console/Site/SiteAddCommand.phpapp/SymfonyApp.phpapp/Console/Site/SiteListCommand.phptests/Unit/Repositories/SiteRepositoryTest.phpapp/Console/Site/SiteDeleteCommand.phptests/Integration/Console/Site/SiteListCommandTest.phptests/Unit/Traits/SiteHelpersTraitTest.php
**/*Command.php
📄 CodeRabbit inference engine (.cursor/rules/01-architecture.mdc)
**/*Command.php: Commands handle user interaction (input/output) and orchestrate services
Commands must not contain business logic; delegate business logic to Services
Commands must not duplicate orchestration logic; extract shared orchestration to Services
Commands should not invoke other commands (no proxy commands)
Use SymfonyStyle consistently for all user-facing console output
Files:
app/Console/Server/ServerDeleteCommand.phpapp/Console/Server/ServerAddCommand.phpapp/Console/Server/ServerListCommand.phpapp/Contracts/BaseCommand.phptests/Fixtures/TestConsoleCommand.phpapp/Console/Site/SiteAddCommand.phpapp/Console/Site/SiteListCommand.phpapp/Console/Site/SiteDeleteCommand.php
app/Console/**/*Command.php
📄 CodeRabbit inference engine (.cursor/rules/03-commands.mdc)
app/Console/**/*Command.php: Never call SymfonyStyle IO directly in commands; use BaseCommand custom IO methods (writeln, hr, h1, success, error, warning, info) exclusively
Use status helper methods (success, error, warning, info) for all status messages to ensure consistent formatting
Use laravel/prompts for all user interactions (text, password, confirm, select, multiselect, suggest, search, spin)
Commands orchestrate services and format all console IO; keep business logic output out of services
Support both interactive prompts and CLI options using getOptionOrPrompt(optionName, promptCallback) for dual-mode commands
Use getValidatedOptionOrPrompt for inputs that require validation; inject validator once and reuse for prompts and options
Define command inputs using OPTIONS only, never ARGUMENTS, to enable getOptionOrPrompt pattern
Follow option naming conventions: --server/--site for selecting existing resources; --name for defining new resource; --host, --port for server config; --yes/-y for confirmations; --skip to bypass validation
Pair every defined option with getOptionOrPrompt to provide both CLI and interactive flows
Boolean flags must use VALUE_NONE; data inputs must use VALUE_REQUIRED
Only --yes gets a short flag (-y); do not assign short flags to other options
Always call showCommandHint() before returning Command::SUCCESS to display non-interactive usage
Files:
app/Console/Server/ServerDeleteCommand.phpapp/Console/Server/ServerAddCommand.phpapp/Console/Server/ServerListCommand.phpapp/Console/Site/SiteAddCommand.phpapp/Console/Site/SiteListCommand.phpapp/Console/Site/SiteDeleteCommand.php
**/*Service.php
📄 CodeRabbit inference engine (.cursor/rules/01-architecture.mdc)
**/*Service.php: Services provide atomic, reusable functionality with no console I/O
Services accept and return plain PHP data types (no console I/O)
Services must be dependency-injected via constructor; declare dependencies in constructor signatures
Extract complex orchestration shared by multiple Commands into dedicated Services
Stateful services should use lazy loading when initialization is expensive or path-dependent
State must be initialized explicitly via public methods (e.g., load(), initialize()) before use
Services should document their stateful nature and initialization requirements
Files:
app/Services/GitService.phpapp/Services/IOService.php
app/Services/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/03-commands.mdc)
Services must return plain data and never perform console IO (no SymfonyStyle, no Laravel Prompts)
Files:
app/Services/GitService.phpapp/Services/IOService.php
{tests/**,test/**,**/*@(Test|Spec).php}
📄 CodeRabbit inference engine (.cursor/rules/00-main.mdc)
Do not run or edit tests unless explicitly instructed
Files:
tests/TestHelpers.phptests/Integration/Console/Server/ServerDeleteCommandTest.phptests/Integration/Console/Site/SiteDeleteCommandTest.phptests/Unit/DTOs/SiteDTOTest.phptests/Unit/Traits/SiteValidationTraitTest.phptests/Unit/Services/GitServiceTest.phptests/Integration/Console/Server/ServerListCommandTest.phptests/Fixtures/TestConsoleCommand.phptests/Integration/Console/Site/SiteAddCommandTest.phptests/Integration/Console/Server/ServerAddCommandTest.phptests/Unit/Repositories/SiteRepositoryTest.phptests/Integration/Console/Site/SiteListCommandTest.phptests/Unit/Traits/SiteHelpersTraitTest.php
tests/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/01-architecture.mdc)
tests/**/*.php: In tests, direct Container instantiation and bind() for mocks is allowed and encouraged for isolation
Do not run PHPStan on test files; tests are excluded from static analysis
tests/**/*.php: Use Pest exclusively with it() syntax for all tests
Unit tests (services/utilities) must use manual instantiation of dependencies
Command/integration tests must use mockCommandContainer() for building commands and overriding services
Use container auto-wiring only when verifying DI configuration or multi-service integration
Keep test files minimal: target under 1.8x the size of the source they cover without sacrificing readability
Test core business logic only; avoid testing the framework itself
Prefer dataset-driven testing using ->with([...]) for multiple scenarios
Eliminate overlapping tests; do not cover the same functionality in multiple tests
Consolidate assertions with chained expectations (expect(...)->toX()->and(...)->toY())
Mock only external dependencies; keep unit tests isolated
Avoid performance tests unless performance is the primary concern
Do not sacrifice readability to meet size/ratio targets
Follow the AAA pattern (Arrange, Act, Assert) in all tests; add Cleanup when needed
For exception tests, combine steps as // ACT & ASSERT when the act triggers the assertion
Organize tests with describe() blocks, beforeEach() setup, and shared helpers/traits for DRY
Avoid meaningless assertions (type-only checks, generic truthiness/nullness, sleeping; use time mocking)
Prefer meaningful assertions invoking real behavior (config values, validators, mocks with expectations)
Unit tests: mock all external dependencies, test single units, run in milliseconds
Integration tests: use real filesystem/externals, cover CLI commands and full workflows
Ignore PHPStan issues in tests; focus on test functionality over strict types
Avoid excessive phpdoc in tests solely to appease types
Files:
tests/TestHelpers.phptests/Integration/Console/Server/ServerDeleteCommandTest.phptests/Integration/Console/Site/SiteDeleteCommandTest.phptests/Unit/DTOs/SiteDTOTest.phptests/Unit/Traits/SiteValidationTraitTest.phptests/Unit/Services/GitServiceTest.phptests/Integration/Console/Server/ServerListCommandTest.phptests/Fixtures/TestConsoleCommand.phptests/Integration/Console/Site/SiteAddCommandTest.phptests/Integration/Console/Server/ServerAddCommandTest.phptests/Unit/Repositories/SiteRepositoryTest.phptests/Integration/Console/Site/SiteListCommandTest.phptests/Unit/Traits/SiteHelpersTraitTest.php
tests/TestHelpers.php
📄 CodeRabbit inference engine (.cursor/rules/02-tests.mdc)
When BaseCommand adds a new service, update mockCommandContainer() in tests/TestHelpers.php by adding a parameter, building or accepting the service, and binding it to the container
Files:
tests/TestHelpers.php
app/{Contracts/BaseCommand.php,Traits/ConsoleOutputTrait.php}
📄 CodeRabbit inference engine (.cursor/rules/03-commands.mdc)
If output functionality is missing, add a new method to BaseCommand/ConsoleOutputTrait with modern styling and documentation
Files:
app/Contracts/BaseCommand.php
app/Contracts/BaseCommand.php
📄 CodeRabbit inference engine (.cursor/rules/03-commands.mdc)
Limit BaseCommand to shared initialization, configuration, and orchestration logic; do not place individual IO operations here
Files:
app/Contracts/BaseCommand.php
app/Traits/*ValidationTrait.php
📄 CodeRabbit inference engine (.cursor/rules/03-commands.mdc)
app/Traits/*ValidationTrait.php: Validation methods must accept mixed input and return ?string (error message or null); do not type-hint to string or throw for basic validation
Use exception-throwing validate*() methods only for heavy I/O validations (e.g., git checks), not for simple input validation
Files:
app/Traits/SiteValidationTrait.php
🧠 Learnings (2)
📚 Learning: 2025-10-12T15:50:03.841Z
Learnt from: CR
PR: bigpixelrocket/deployer-php#0
File: .cursor/rules/02-tests.mdc:0-0
Timestamp: 2025-10-12T15:50:03.841Z
Learning: Applies to tests/TestHelpers.php : When BaseCommand adds a new service, update mockCommandContainer() in tests/TestHelpers.php by adding a parameter, building or accepting the service, and binding it to the container
Applied to files:
tests/TestHelpers.phptests/Fixtures/TestConsoleCommand.phptests/Integration/Console/Server/ServerAddCommandTest.php
📚 Learning: 2025-10-12T15:50:03.841Z
Learnt from: CR
PR: bigpixelrocket/deployer-php#0
File: .cursor/rules/02-tests.mdc:0-0
Timestamp: 2025-10-12T15:50:03.841Z
Learning: Applies to tests/**/*.php : Command/integration tests must use mockCommandContainer() for building commands and overriding services
Applied to files:
tests/TestHelpers.php
🧬 Code graph analysis (24)
app/Console/Server/ServerDeleteCommand.php (2)
app/Repositories/SiteRepository.php (1)
findByServer(111-124)app/Services/IOService.php (2)
writeln(458-464)error(493-496)
app/Services/GitService.php (1)
app/Services/ProcessService.php (2)
ProcessService(12-49)run(33-48)
app/DTOs/SiteDTO.php (1)
app/DTOs/ServerDTO.php (1)
ServerDTO(7-17)
tests/TestHelpers.php (2)
app/Services/GitService.php (1)
GitService(12-81)app/Container.php (1)
bind(46-50)
app/Repositories/SiteRepository.php (1)
app/DTOs/SiteDTO.php (2)
SiteDTO(7-32)isLocal(28-31)
tests/Integration/Console/Server/ServerDeleteCommandTest.php (2)
app/DTOs/ServerDTO.php (1)
ServerDTO(7-17)app/Console/Server/ServerDeleteCommand.php (1)
execute(40-115)
tests/Integration/Console/Site/SiteDeleteCommandTest.php (3)
app/DTOs/SiteDTO.php (1)
SiteDTO(7-32)tests/TestHelpers.php (1)
mockCommandContainer(365-407)app/Container.php (1)
build(59-85)
app/Console/Server/ServerListCommand.php (3)
app/Services/IOService.php (2)
h1(501-507)writeln(458-464)app/Traits/ServerHelpersTrait.php (2)
displayServerDeets(74-84)ServerHelpersTrait(20-86)app/Repositories/SiteRepository.php (1)
findByServer(111-124)
tests/Unit/DTOs/SiteDTOTest.php (1)
app/DTOs/SiteDTO.php (2)
isLocal(28-31)SiteDTO(7-32)
app/Contracts/BaseCommand.php (1)
app/Services/GitService.php (1)
GitService(12-81)
app/Traits/SiteValidationTrait.php (3)
app/Repositories/SiteRepository.php (1)
findByDomain(75-86)app/Services/ProcessService.php (1)
run(33-48)app/Repositories/ServerRepository.php (1)
findByName(70-81)
tests/Unit/Traits/SiteValidationTraitTest.php (2)
app/Traits/SiteValidationTrait.php (5)
validateDomainInput(19-38)validateBranchInput(45-56)validateRepoInput(63-90)validateGitRepo(97-123)validateServers(131-143)tests/TestHelpers.php (2)
mockSiteRepository(320-333)mockServerRepository(294-307)
tests/Unit/Services/GitServiceTest.php (2)
tests/TestHelpers.php (1)
mockGitService(271-275)app/Services/GitService.php (2)
detectRemoteUrl(28-50)detectCurrentBranch(58-80)
tests/Integration/Console/Server/ServerListCommandTest.php (4)
app/DTOs/SiteDTO.php (1)
SiteDTO(7-32)app/DTOs/ServerDTO.php (1)
ServerDTO(7-17)app/Console/Server/ServerListCommand.php (1)
execute(28-77)tests/Unit/Contracts/BaseCommandTest.php (2)
execute(29-34)inventory(79-107)
app/Traits/SiteHelpersTrait.php (5)
app/DTOs/ServerDTO.php (1)
ServerDTO(7-17)app/DTOs/SiteDTO.php (2)
SiteDTO(7-32)isLocal(28-31)app/Repositories/ServerRepository.php (2)
ServerRepository(15-189)findByName(70-81)app/Repositories/SiteRepository.php (2)
SiteRepository(15-208)findByDomain(75-86)app/Services/IOService.php (7)
IOService(30-578)warning(485-488)writeln(458-464)getOptionOrPrompt(84-132)promptSelect(304-322)error(493-496)promptMultiselect(337-357)
tests/Fixtures/TestConsoleCommand.php (6)
app/Services/GitService.php (1)
GitService(12-81)app/Services/IOService.php (1)
IOService(30-578)app/Repositories/ServerRepository.php (1)
ServerRepository(15-189)app/Repositories/SiteRepository.php (1)
SiteRepository(15-208)app/Contracts/BaseCommand.php (1)
__construct(36-53)app/Traits/SiteHelpersTrait.php (3)
displaySiteDeets(127-143)selectServers(81-122)selectSite(29-71)
tests/Integration/Console/Site/SiteAddCommandTest.php (3)
app/DTOs/ServerDTO.php (1)
ServerDTO(7-17)tests/TestHelpers.php (1)
mockCommandContainer(365-407)app/Container.php (1)
build(59-85)
tests/Integration/Console/Server/ServerAddCommandTest.php (2)
tests/TestHelpers.php (1)
mockCommandContainer(365-407)tests/Fixtures/MockSSHService.php (1)
MockSSHService(27-87)
app/Console/Site/SiteAddCommand.php (6)
app/Contracts/BaseCommand.php (1)
BaseCommand(27-152)app/DTOs/SiteDTO.php (2)
SiteDTO(7-32)isLocal(28-31)app/Services/IOService.php (11)
hr(512-518)h1(501-507)warning(485-488)writeln(458-464)getValidatedOptionOrPrompt(159-182)promptText(200-218)getOptionOrPrompt(84-132)promptSelect(304-322)error(493-496)success(477-480)showCommandHint(525-561)app/Traits/SiteValidationTrait.php (4)
validateDomainInput(19-38)validateRepoInput(63-90)validateBranchInput(45-56)validateServers(131-143)app/Services/GitService.php (2)
detectRemoteUrl(28-50)detectCurrentBranch(58-80)app/Traits/SiteHelpersTrait.php (2)
selectServers(81-122)displaySiteDeets(127-143)
app/Console/Site/SiteListCommand.php (3)
app/Contracts/BaseCommand.php (1)
BaseCommand(27-152)app/Services/IOService.php (4)
hr(512-518)warning(485-488)writeln(458-464)h1(501-507)app/Traits/SiteHelpersTrait.php (1)
displaySiteDeets(127-143)
tests/Unit/Repositories/SiteRepositoryTest.php (4)
app/DTOs/SiteDTO.php (2)
SiteDTO(7-32)isLocal(28-31)app/Repositories/SiteRepository.php (6)
create(55-67)findByDomain(75-86)all(93-103)SiteRepository(15-208)loadInventory(35-47)findByServer(111-124)tests/TestHelpers.php (1)
mockInventoryService(143-159)app/Services/InventoryService.php (1)
loadInventoryFile(97-111)
app/Console/Site/SiteDeleteCommand.php (3)
app/Contracts/BaseCommand.php (1)
BaseCommand(27-152)app/Services/IOService.php (8)
hr(512-518)h1(501-507)writeln(458-464)getOptionOrPrompt(84-132)promptConfirm(260-276)warning(485-488)success(477-480)showCommandHint(525-561)app/Traits/SiteHelpersTrait.php (2)
selectSite(29-71)displaySiteDeets(127-143)
tests/Integration/Console/Site/SiteListCommandTest.php (3)
app/DTOs/SiteDTO.php (1)
SiteDTO(7-32)tests/TestHelpers.php (1)
mockCommandContainer(365-407)app/Container.php (1)
build(59-85)
tests/Unit/Traits/SiteHelpersTraitTest.php (3)
app/DTOs/SiteDTO.php (1)
SiteDTO(7-32)tests/TestHelpers.php (1)
mockCommandContainer(365-407)tests/Fixtures/TestConsoleCommand.php (2)
TestConsoleCommand(29-295)setTestMethod(67-71)
🪛 GitHub Actions: Rector
app/Services/GitService.php
[error] 9-9: vendor/bin/rector --dry-run: 1 file would be changed by Rector (ReadOnlyClassRector). Process exited with code 2.
🔇 Additional comments (65)
.gitignore (1)
2-2: LGTM!The addition of
.cursor/.agent-tools/to the ignore list is appropriate for excluding IDE-specific tooling artifacts.app/Console/Server/ServerDeleteCommand.php (2)
60-75: LGTM! Good referential integrity guard.The pre-deletion check prevents orphaning sites by blocking server deletion when sites are still associated. The error message clearly lists the blocking sites and provides actionable feedback.
80-80: LGTM! Improved visual separation.The blank line before the confirmation prompt improves readability and user experience.
app/Services/IOService.php (1)
175-175: LGTM! Consistent error formatting.The blank line after validation errors harmonizes the output formatting with other error-handling flows in the codebase, improving readability.
app/SymfonyApp.php (1)
11-13: LGTM! Proper command registration.The new Site commands are correctly imported and registered, following the same pattern as the existing Server commands. The implementation maintains consistency with the established command registration approach.
Also applies to: 126-128
app/Console/Server/ServerListCommand.php (2)
9-9: LGTM! Trait integration for site functionality.The addition of
SiteHelpersTraitenables site-related operations in the server list command, supporting the server-site relationship display.Also applies to: 22-22
54-73: LGTM! Enhanced server listing with site associations.The server list now displays associated sites for each server and adds visual separators between entries, significantly improving the information density and readability of the command output. The implementation correctly uses
findByServer()to retrieve site associations.tests/Unit/Services/GitServiceTest.php (1)
28-43: LGTM! Comprehensive error handling and edge case coverage.The tests properly validate:
- Null returns for non-git directories (with proper cleanup)
- Null returns for invalid directories
- Whitespace trimming behavior
The test structure follows AAA pattern with appropriate use of
finallyblocks for cleanup.Also applies to: 75-90, 45-54, 92-101, 103-118
tests/Unit/DTOs/SiteDTOTest.php (2)
8-23: LGTM! Comprehensive git site validation.The test correctly validates all properties of a git-based site, including the new
isLocal()method returning false for sites with a repository.
25-40: LGTM! Local site support validated.The new test case properly validates local sites without git repositories, ensuring
isLocal()returns true when bothrepoandbranchare null.app/Console/Server/ServerAddCommand.php (1)
20-20: Verify removal of SSH connectivity testing is intentional.The command has been significantly simplified by removing:
- SSH connectivity verification flow
--skipoption to bypass verification--yesoption for auto-confirmation- Connection failure handling and guidance
While this simplifies the code, servers can now be added without verifying they're reachable, potentially leading to configuration errors being discovered later during actual deployment rather than at registration time.
Confirm this behavior change aligns with the intended user experience and that SSH verification is handled elsewhere in the workflow (e.g., at deployment time).
Also applies to: 41-41, 147-173
tests/Integration/Console/Site/SiteAddCommandTest.php (4)
47-72: LGTM!The test correctly validates the non-interactive addition of a git site with all required options, asserting both the exit code and expected output fragments.
74-95: LGTM!The test properly validates the addition of a local site (without repo/branch) and verifies the output contains the "Local" type indicator.
161-165: LGTM!Good use of data providers to cover multiple invalid domain scenarios with a single test case.
188-191: LGTM!Appropriate data provider coverage for invalid branch scenarios.
tests/TestHelpers.php (3)
10-10: LGTM!Import properly added for the new GitService mock.
261-276: LGTM!The
mockGitService()helper follows the established pattern of other service mocks. It correctly wraps aProcessServiceto enable git command execution testing without real processes.
365-407: LGTM!GitService is properly integrated into
mockCommandContainer():
- Added as an optional parameter (line 368)
- Initialized with default if not provided (line 388)
- Bound to the container (line 398)
The parameter order and binding sequence match BaseCommand's constructor order, as required by the coding guidelines.
Based on learnings
tests/Integration/Console/Site/SiteListCommandTest.php (2)
48-82: LGTM!Good use of data providers to test multiple listing scenarios. The assertions correctly verify both the exit code and expected output fragments.
88-102: LGTM!Properly validates the empty inventory case with appropriate warning message and guidance to add sites.
app/Repositories/SiteRepository.php (3)
105-124: LGTM!The
findByServermethod correctly filters sites by server name usingin_arraywith strict comparison. This enables features like preventing server deletion when sites depend on it.
172-186: LGTM!The conditional inclusion of
repoandbranchonly for git-based sites (using!$site->isLocal()) properly aligns with the SiteDTO contract where these fields are nullable for local sites.
194-207: LGTM!The hydration logic correctly treats
repoandbranchas nullable strings, properly supporting local sites where these fields are absent from inventory data.app/Console/Site/SiteListCommand.php (2)
1-21: LGTM!The command class is properly structured:
- Extends
BaseCommand- Uses
SiteHelpersTraitfor display logic- Correctly annotated with
#[AsCommand]attribute
26-54: LGTM!The execute method follows the correct pattern:
- Calls
parent::executeto initialize base services- Properly handles empty inventory with a warning and guidance
- Uses
displaySiteDeetsfromSiteHelpersTraitfor consistent formatting- Returns appropriate exit codes
tests/Integration/Console/Site/SiteDeleteCommandTest.php (3)
16-34: LGTM!The test helper correctly prepares inventory data with raw site arrays, matching the pattern used in
SiteAddCommandTestandServerDeleteCommandTest.
45-66: LGTM!The test properly validates non-interactive deletion with appropriate assertions on exit code and output fragments.
72-90: LGTM!Correctly tests the error path for attempting to delete a non-existent site.
tests/Unit/Traits/SiteValidationTraitTest.php (5)
13-64: LGTM!The
TestSiteValidatorfixture properly exposes protected validation methods for testing while maintaining the trait's original access levels in production code.
81-98: LGTM!Comprehensive coverage of valid domain formats using a data provider.
149-165: LGTM!Good coverage of valid branch name patterns, including feature branches, bugfixes, and release branches.
195-213: LGTM!Thorough validation of repository URL formats across different Git hosting providers and protocols.
265-299: LGTM!Proper coverage of server validation edge cases, including empty arrays, non-existent servers, and validation success scenarios.
tests/Integration/Console/Server/ServerDeleteCommandTest.php (2)
16-36: LGTM!The test helper is correctly updated to accept and populate site inventory data. The explicit structure with both
serversandsiteskeys (even when empty) makes the inventory format clearer.
109-134: LGTM!The new test properly validates that server deletion is prevented when sites depend on it. The assertions correctly verify:
- Failure exit code
- Error indicator and message
- Display of associated site domains
This aligns with the
findByServerfunctionality added toSiteRepository.app/DTOs/SiteDTO.php (1)
19-21: LGTM: Nullable repo/branch + isLocal()API change is consistent and small helper isLocal() is clear.
Also applies to: 25-31
tests/Unit/Repositories/SiteRepositoryTest.php (3)
36-41: CRUD path coverage looks solidGood end-to-end checks for create/find/all/delete, covering both git and local sites and isLocal().
Also applies to: 42-50, 51-59, 63-68, 69-77
97-121: Server filtering tests are clear and preserve input orderfindByServer() behavior and expected ordering are well asserted.
159-223: Hydration robustness scenarios are thoroughGood handling of missing/wrong types for domain/repo/branch/servers. This matches the repository’s defensive hydration.
app/Console/Site/SiteDeleteCommand.php (1)
27-34: Options follow project conventions--site VALUE_REQUIRED and --yes with -y are aligned with our CLI rules.
app/Contracts/BaseCommand.php (1)
11-12: LGTM: GitService DI added cleanlyConstructor and imports updated; tests/helpers already wire GitService accordingly.
Also applies to: 36-51
tests/Integration/Console/Server/ServerAddCommandTest.php (1)
15-20: LGTM: helper simplified; tests updated accordinglycreateServerAddCommandTester() no longer requires SSH service; all call sites updated. Assertions remain meaningful.
Also applies to: 31-35, 57-60, 86-89, 112-115, 139-142, 173-176
tests/Unit/Traits/SiteHelpersTraitTest.php (1)
23-33: LGTM: covers display and server selection paths wellGood coverage for git/local display formatting and server validation via CLI options.
Also applies to: 54-63, 87-103, 105-119
tests/Integration/Console/Server/ServerListCommandTest.php (5)
17-49: LGTM!The helper function correctly extends the test setup to support sites alongside servers. The inventory data structure properly maps both ServerDTO and SiteDTO fields to the expected format.
60-85: LGTM!The test case appropriately validates server listing with full details. The descriptive test name and comprehensive assertions ensure the command displays all required server information.
107-128: LGTM!Excellent use of dataset-driven testing to verify SSH key path display. The test covers both default and custom key scenarios concisely.
134-168: LGTM!The test effectively verifies site display under servers with ordering checks. The position-based assertions ensure sites appear after their respective servers in the output.
170-185: LGTM!The test correctly validates that no "Sites:" section is displayed when a server has no associated sites.
app/Console/Site/SiteAddCommand.php (6)
32-42: LGTM!The option configuration follows guidelines by using OPTIONS only and VALUE_REQUIRED for all data inputs, enabling the getOptionOrPrompt pattern.
59-70: LGTM!The server availability check provides clear user guidance and prevents proceeding without servers, ensuring data integrity.
75-89: LGTM!Domain input properly uses validated option/prompt pattern with early return on validation failure. The flow correctly handles both CLI and interactive modes.
94-150: LGTM!Site type selection and git-specific details collection are well-structured. The use of GitService for default detection enhances user experience, and validation ensures data integrity.
155-172: LGTM!Server selection and validation properly handle errors with user-friendly messages and early returns on failure.
177-219: LGTM!The final section correctly creates the DTO, persists the site with error handling, and displays the command hint as per guidelines. The conditional hint options for local vs git sites are appropriate.
app/Traits/SiteValidationTrait.php (4)
19-38: LGTM!Domain validation correctly checks type, format, and uniqueness. The use of
FILTER_VALIDATE_DOMAINensures proper domain name validation.
45-56: LGTM!Branch name validation appropriately checks for non-empty strings without over-complicating the logic.
97-123: LGTM!Git repository validation correctly uses exception-throwing for the I/O-heavy remote check, following the guideline for heavy validations. The timeout and error handling are appropriate.
131-143: LGTM!Server validation correctly ensures at least one server is selected and validates each server's existence in inventory.
tests/Fixtures/TestConsoleCommand.php (4)
12-12: LGTM!Import and trait additions correctly support the new GitService dependency and SiteHelpersTrait functionality in the test fixture.
Also applies to: 18-18, 32-32
42-42: LGTM!Constructor updates correctly integrate GitService, following the pattern for updating test fixtures when BaseCommand adds a new service. Based on learnings.
Also applies to: 50-61
79-79: LGTM!The 'servers' option addition supports testing server selection functionality from SiteHelpersTrait.
96-98: LGTM!New match cases enable testing of SiteHelpersTrait methods, following the established pattern for test method dispatch.
app/Traits/SiteHelpersTrait.php (3)
29-71: LGTM!The
selectSitemethod provides excellent UX with helpful guidance when no sites exist. The return structure with both site and exit_code enables flexible handling by callers.
127-143: LGTM!The
displaySiteDeetsmethod correctly differentiates between local and git sites, displaying appropriate details for each type with consistent formatting.
81-122: selectServers array transformation is safe: upstream validation andfindByNameprevent empty names, soarray_filterwon’t drop any valid entries.
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (1)
app/Services/GitService.php (1)
12-16: Fix Rector failure: declare class as readonly.The class is immutable and the pipeline fails (ReadOnlyClassRector). Declare it as
readonlyto satisfy Rector and PHP 8.2+ guidelines.Apply this diff:
-final class GitService +final readonly class GitService { public function __construct(private ProcessService $proc) { }Then re-run Rector and Pint. Based on pipeline failures and coding guidelines.
🧹 Nitpick comments (1)
app/Services/GitService.php (1)
28-80: Consider extracting a helper to reduce duplication.Both
detectRemoteUrlanddetectCurrentBranchduplicate the getcwd() handling, try-catch structure, and trim/return pattern. Extracting a private helper (e.g.,runGitCommand(array $cmd, ?string $workingDir): ?string) would reduce repetition and improve maintainability.Example refactor:
/** * Run a git command and return trimmed output or null on failure. * * @param list<string> $cmd Git command and arguments * @param string|null $workingDir Working directory (defaults to current) * @return string|null Command output or null on failure */ private function runGitCommand(array $cmd, ?string $workingDir): ?string { try { $cwd = $workingDir ?? getcwd(); if ($cwd === false) { return null; } $process = $this->proc->run($cmd, $cwd, 2.0); if ($process->isSuccessful()) { return trim($process->getOutput()); } return null; } catch (\Exception) { return null; } } public function detectRemoteUrl(?string $workingDir = null): ?string { return $this->runGitCommand( ['git', 'config', '--get', 'remote.origin.url'], $workingDir ); } public function detectCurrentBranch(?string $workingDir = null): ?string { return $this->runGitCommand( ['git', 'rev-parse', '--abbrev-ref', 'HEAD'], $workingDir ); }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
app/Services/GitService.php(1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.php
📄 CodeRabbit inference engine (.cursor/rules/00-main.mdc)
**/*.php: Eliminate single-use private methods by inlining them directly
Cache expensive computed values by initializing them in the constructor instead of recomputing
Prefer direct property access over method calls when appropriate to avoid call overhead
Organize code into comment-separated sections; prefer alphabetical ordering when it does not conflict with logical grouping
**/*.php: Adhere to PSR-12 coding style in all PHP files
Declare strict_types=1 at the top of every PHP file
Prefer PHP 8.x features (union types, match, attributes, readonly) where appropriate
Always import classes with use statements; avoid fully qualified class names in code bodies
All methods must declare explicit return types; use proper generics in types/docblocks (e.g., Collection<int, User>)
Use dependency injection instead of manually resolving or instantiating classes
Prefer Symfony component classes (e.g., Filesystem, Process) over native PHP functions for testability
All object creation must use $container->build(ClassName::class) instead of new, except for value objects/DTOs/pure data structures
In production code, access the Container via constructor injection, not via static/global access
Add minimal DocBlock comments with descriptions, parameters, and return types for classes and functions
Use comments as visual separators for sections/subsections with a single newline between header, subheader, and paragraph; avoid obvious or stale comments
Run rector on changed PHP files before completing a task
Run pint on changed PHP files to fix code style before completing a task
Files:
app/Services/GitService.php
**/*Service.php
📄 CodeRabbit inference engine (.cursor/rules/01-architecture.mdc)
**/*Service.php: Services provide atomic, reusable functionality with no console I/O
Services accept and return plain PHP data types (no console I/O)
Services must be dependency-injected via constructor; declare dependencies in constructor signatures
Extract complex orchestration shared by multiple Commands into dedicated Services
Stateful services should use lazy loading when initialization is expensive or path-dependent
State must be initialized explicitly via public methods (e.g., load(), initialize()) before use
Services should document their stateful nature and initialization requirements
Files:
app/Services/GitService.php
app/Services/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/03-commands.mdc)
Services must return plain data and never perform console IO (no SymfonyStyle, no Laravel Prompts)
Files:
app/Services/GitService.php
🧬 Code graph analysis (1)
app/Services/GitService.php (1)
app/Services/ProcessService.php (2)
ProcessService(12-49)run(33-48)
Extract common git command execution pattern from detectRemoteUrl() and detectCurrentBranch() into a private runGitCommand() helper method. This reduces code duplication and improves maintainability by centralizing git command execution logic in a single place.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
app/Services/GitService.php (1)
61-79: Consider extracting timeout constant.The implementation correctly handles
getcwd()returning false and catches exceptions appropriately for a non-fatal detection service. However, the hardcoded2.0timeout could be a private class constant for easier maintenance.Apply this diff to extract the timeout:
final readonly class GitService { + private const float GIT_COMMAND_TIMEOUT = 2.0; + public function __construct(private ProcessService $proc)Then update line 69:
- $process = $this->proc->run($cmd, $cwd, 2.0); + $process = $this->proc->run($cmd, $cwd, self::GIT_COMMAND_TIMEOUT);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
app/Services/GitService.php(1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.php
📄 CodeRabbit inference engine (.cursor/rules/00-main.mdc)
**/*.php: Eliminate single-use private methods by inlining them directly
Cache expensive computed values by initializing them in the constructor instead of recomputing
Prefer direct property access over method calls when appropriate to avoid call overhead
Organize code into comment-separated sections; prefer alphabetical ordering when it does not conflict with logical grouping
**/*.php: Adhere to PSR-12 coding style in all PHP files
Declare strict_types=1 at the top of every PHP file
Prefer PHP 8.x features (union types, match, attributes, readonly) where appropriate
Always import classes with use statements; avoid fully qualified class names in code bodies
All methods must declare explicit return types; use proper generics in types/docblocks (e.g., Collection<int, User>)
Use dependency injection instead of manually resolving or instantiating classes
Prefer Symfony component classes (e.g., Filesystem, Process) over native PHP functions for testability
All object creation must use $container->build(ClassName::class) instead of new, except for value objects/DTOs/pure data structures
In production code, access the Container via constructor injection, not via static/global access
Add minimal DocBlock comments with descriptions, parameters, and return types for classes and functions
Use comments as visual separators for sections/subsections with a single newline between header, subheader, and paragraph; avoid obvious or stale comments
Run rector on changed PHP files before completing a task
Run pint on changed PHP files to fix code style before completing a task
Files:
app/Services/GitService.php
**/*Service.php
📄 CodeRabbit inference engine (.cursor/rules/01-architecture.mdc)
**/*Service.php: Services provide atomic, reusable functionality with no console I/O
Services accept and return plain PHP data types (no console I/O)
Services must be dependency-injected via constructor; declare dependencies in constructor signatures
Extract complex orchestration shared by multiple Commands into dedicated Services
Stateful services should use lazy loading when initialization is expensive or path-dependent
State must be initialized explicitly via public methods (e.g., load(), initialize()) before use
Services should document their stateful nature and initialization requirements
Files:
app/Services/GitService.php
app/Services/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/03-commands.mdc)
Services must return plain data and never perform console IO (no SymfonyStyle, no Laravel Prompts)
Files:
app/Services/GitService.php
🧬 Code graph analysis (1)
app/Services/GitService.php (1)
app/Services/ProcessService.php (2)
ProcessService(12-49)run(33-48)
🔇 Additional comments (3)
app/Services/GitService.php (3)
1-16: LGTM! Clean service setup.The class properly declares
strict_types, usesfinal readonlyfor PHP 8.2+ immutability, and injects ProcessService via constructor. The structure follows coding guidelines for services.
18-34: LGTM! Clean delegation pattern.The method properly delegates to the private helper, has complete DocBlock documentation, and uses the visual separator as required by coding guidelines.
36-48: LGTM! Consistent with detectRemoteUrl.The method follows the same clean delegation pattern and has complete documentation.
Summary by CodeRabbit
New Features
Bug Fixes
Chores