Skip to content

feat: add site:shared push pull commands for shared files - #92

Merged
loadinglucian merged 3 commits into
mainfrom
feat/site-shared-push-pull
Nov 17, 2025
Merged

feat: add site:shared push pull commands for shared files#92
loadinglucian merged 3 commits into
mainfrom
feat/site-shared-push-pull

Conversation

@loadinglucian

@loadinglucian loadinglucian commented Nov 17, 2025

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • New Features
    • Added console command to download files from a site's shared directory (domain, remote path, local destination; prompts and overwrite handling).
    • Added console command to upload local files to a site's shared directory (domain, local path, remote filename; creates directories, sets permissions/ownership, and shows replay command).
  • Improvements
    • Enhanced site/server validation and path handling for shared file operations.

@coderabbitai

coderabbitai Bot commented Nov 17, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Adds two new Symfony Console commands to upload and download files to a site's shared directory, a trait for normalizing and building shared paths, server lookup helper for sites, and site-path/validation helpers in SitesTrait.

Changes

Cohort / File(s) Summary
New Console Commands
app/Console/Site/SiteSharedPullCommand.php, app/Console/Site/SiteSharedPushCommand.php
Added site:shared:pull and site:shared:push commands. Pull downloads a file from a site's shared directory to a local path; Push uploads a local file into a site's shared directory. Both perform site selection, server lookup, SSH connectivity checks, path resolution (prompts/defaults), existence checks, upload/download via SSH, permission/ownership handling (push), and consistent error handling with command replay output.
Site shared path helpers
app/Traits/SiteSharedPathsTrait.php
New trait with normalizeRelativePath(string): ?string (normalize/collapse slashes, strip leading slash, disallow "..", validate non-empty) and buildSharedPath(SiteDTO, string $relative = ''): string (concatenate site shared root and relative path).
Servers helper
app/Traits/ServersTrait.php
Added `protected function getServerForSite(SiteDTO $site): ServerDTO
Sites helpers & validation
app/Traits/SitesTrait.php
Added protected function getSiteRootPath(SiteDTO $site): string and protected function getSiteSharedPath(SiteDTO $site): string. Enhanced validations: domain uniqueness check in validateSiteDomain, and non-empty checks for branch and repository in validateSiteBranch/validateSiteRepo. Minor formatting adjustments.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant CLI
    participant PullCmd as SiteSharedPullCommand
    participant Sites as SitesTrait
    participant Servers as ServersTrait
    participant SSH

    User->>CLI: site:shared:pull --domain=example.com --remote=config.php --local=./config.php
    CLI->>PullCmd: execute()
    PullCmd->>Sites: get site by domain
    Sites-->>PullCmd: SiteDTO
    PullCmd->>Servers: getServerForSite(site)
    Servers-->>PullCmd: ServerDTO
    PullCmd->>PullCmd: resolveRemotePath() -> normalizeRelativePath()
    PullCmd->>SSH: test -f /shared/config.php
    SSH-->>PullCmd: exists / not found
    PullCmd->>PullCmd: resolveLocalPath() (prompt/expand)
    PullCmd->>SSH: downloadFile(/shared/config.php → ./config.php)
    SSH-->>PullCmd: success / error
    PullCmd-->>User: success message + replay
Loading
sequenceDiagram
    actor User
    participant CLI
    participant PushCmd as SiteSharedPushCommand
    participant Sites as SitesTrait
    participant Servers as ServersTrait
    participant SSH

    User->>CLI: site:shared:push --domain=example.com --local=./config.php --remote=config.php
    CLI->>PushCmd: execute()
    PushCmd->>Sites: get site by domain
    Sites-->>PushCmd: SiteDTO
    PushCmd->>Servers: getServerForSite(site)
    Servers-->>PushCmd: ServerDTO
    PushCmd->>PushCmd: resolveLocalPath() (expand & validate file)
    PushCmd->>PushCmd: resolveRemotePath() -> normalizeRelativePath()
    PushCmd->>PushCmd: buildSharedPath(site, remote)
    PushCmd->>SSH: mkdir -p /shared/... && uploadFile()
    SSH-->>PushCmd: upload result
    PushCmd->>SSH: chmod 640 && chown deployer:deployer (if needed)
    SSH-->>PushCmd: success / error
    PushCmd-->>User: success message + replay
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Files/areas to focus on:
    • Path normalization rules in SiteSharedPathsTrait (edge cases: leading/trailing slashes, multiple slashes, "..").
    • SSH command composition, exit-code handling and exception messages in push/pull commands.
    • Permission/ownership logic after upload (conditional chown) and use of deployer username.
    • getServerForSite return typing (ServerDTO|int) and the calling sites' handling of Command::FAILURE.
    • Domain uniqueness and repository/branch validation logic correctness and inventory query.

Possibly related PRs

  • bigpixelrocket/deployer-php#62 — Adds/changes server info and server validation utilities used by the new commands (serverInfo usage).
  • bigpixelrocket/deployer-php#46 — Introduces related site commands, site validation helpers, and DTO/repository changes that the new commands integrate with.
  • bigpixelrocket/deployer-php#64 — Modifies ServersTrait/SitesTrait foundations that are extended by these changes (server/site helper consolidation).

Poem

🐇 I nibbled paths and chewed the slashes tight,
I tunneled SSH by moonlit night,
I pulled a config, then pushed it home,
Shared folders safe where rabbits roam. 🥕📁

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately and concisely describes the main changes: adding two new console commands (site:shared:push and site:shared:pull) for managing shared files, which aligns with the file additions and trait enhancements.
Docstring Coverage ✅ Passed Docstring coverage is 83.87% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/site-shared-push-pull

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a3d2da8 and 0a3154b.

📒 Files selected for processing (1)
  • app/Traits/SiteSharedPathsTrait.php (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/Traits/SiteSharedPathsTrait.php

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
app/Traits/SitesTrait.php (1)

207-221: Inline getSiteRootPath into getSiteSharedPath to eliminate the single-use helper method.

The method is called only once (line 220), which directly aligns with the coding guideline to eliminate single-use methods. Replace line 220:

return $this->getSiteRootPath($site).'/shared';

with:

return '/home/deployer/sites/'.$site->domain.'/shared';

Then remove the getSiteRootPath method entirely (lines 207–213).

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8ccff91 and a3d2da8.

📒 Files selected for processing (5)
  • app/Console/Site/SiteSharedPullCommand.php (1 hunks)
  • app/Console/Site/SiteSharedPushCommand.php (1 hunks)
  • app/Traits/ServersTrait.php (14 hunks)
  • app/Traits/SiteSharedPathsTrait.php (1 hunks)
  • app/Traits/SitesTrait.php (6 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.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

Files:

  • app/Traits/ServersTrait.php
  • app/Traits/SiteSharedPathsTrait.php
  • app/Console/Site/SiteSharedPushCommand.php
  • app/Console/Site/SiteSharedPullCommand.php
  • app/Traits/SitesTrait.php
🧠 Learnings (1)
📚 Learning: 2025-09-22T11:10:21.459Z
Learnt from: CR
Repo: deployer-plus/deployer-php PR: 0
File: .cursor/rules/01-architecture.mdc:0-0
Timestamp: 2025-09-22T11:10:21.459Z
Learning: Applies to app/**/Command/**/*.php : Commands must not duplicate orchestration logic—extract to shared Services

Applied to files:

  • app/Console/Site/SiteSharedPullCommand.php
🧬 Code graph analysis (3)
app/Traits/SiteSharedPathsTrait.php (3)
app/DTOs/SiteDTO.php (1)
  • SiteDTO (7-24)
app/Contracts/BaseCommand.php (1)
  • nay (186-190)
app/Traits/SitesTrait.php (1)
  • getSiteSharedPath (218-221)
app/Console/Site/SiteSharedPushCommand.php (6)
app/DTOs/ServerDTO.php (1)
  • ServerDTO (7-19)
app/Traits/SitesTrait.php (1)
  • selectSite (70-106)
app/Traits/ServersTrait.php (1)
  • getServerForSite (532-543)
app/Traits/SiteSharedPathsTrait.php (2)
  • buildSharedPath (37-46)
  • normalizeRelativePath (15-35)
app/Services/SSHService.php (2)
  • uploadFile (109-132)
  • executeCommand (69-102)
app/Services/FilesystemService.php (2)
  • expandPath (113-143)
  • exists (42-45)
app/Traits/SitesTrait.php (1)
app/DTOs/SiteDTO.php (1)
  • SiteDTO (7-24)
🪛 GitHub Actions: Pint
app/Traits/SiteSharedPathsTrait.php

[error] Pint PSR-12 lint failure: single_blank_line_at_eof.

🔇 Additional comments (8)
app/Traits/SitesTrait.php (1)

136-205: LGTM on validation enhancements.

The added uniqueness check for domains and non-empty validations for branch and repository fields strengthen data integrity and prevent configuration errors.

app/Traits/ServersTrait.php (1)

529-543: LGTM on the new server lookup helper.

The getServerForSite method provides a clean abstraction for resolving a site's associated server with appropriate error handling, reducing duplication across commands.

app/Traits/SiteSharedPathsTrait.php (1)

28-32: LGTM on path traversal protection.

The validation correctly prevents directory traversal attacks by rejecting paths containing .., which is essential for the security of file operations in the shared directory.

app/Console/Site/SiteSharedPullCommand.php (2)

48-168: LGTM on command execution flow.

The command structure is clean with proper error handling at each step, overwrite protection, and clear user feedback. The workflow logically progresses through site selection, server validation, path resolution, and file download.


218-237: LGTM on remote file existence check.

The implementation correctly uses the Unix test -f command with proper exit code handling and shell escaping. The exception for unexpected errors provides good debugging information.

app/Console/Site/SiteSharedPushCommand.php (3)

48-143: LGTM on upload logic and permissions.

The upload sequence (mkdir, upload, chmod 640, conditional chown) is correct and secure. The chmod 640 permission is appropriate for shared files, allowing the owner to read/write and the group to read. The conditional chown based on username prevents unnecessary operations.


149-176: LGTM on local file validation.

The method properly validates that the local file exists and is a regular file (not a directory), with clear error messages. Path expansion for ~ notation is a nice UX touch.


202-211: LGTM on remote command helper.

The helper provides clean error handling for remote commands, with informative error messages that include command output when available, aiding in debugging failures.

Comment thread app/Traits/SiteSharedPathsTrait.php
Comment thread app/Traits/SiteSharedPathsTrait.php Outdated
…ivePath

The null check catches rare preg_replace() errors, not empty input.
Empty input is already handled separately on line 28.
Updated message to accurately reflect processing failure rather than missing input.
@loadinglucian
loadinglucian merged commit 401ed45 into main Nov 17, 2025
5 checks passed
@loadinglucian
loadinglucian deleted the feat/site-shared-push-pull branch November 17, 2025 19:51
This was referenced Nov 18, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant