Skip to content

feat: add dedicated install-php playbook and command - #80

Merged
loadinglucian merged 3 commits into
mainfrom
feat/dedicated-install-php
Nov 11, 2025
Merged

feat: add dedicated install-php playbook and command#80
loadinglucian merged 3 commits into
mainfrom
feat/dedicated-install-php

Conversation

@loadinglucian

@loadinglucian loadinglucian commented Nov 11, 2025

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • New Features

    • New CLI command to install PHP with selectable version and optional set-as-default; command replays chosen parameters.
    • Server info now lists all detected PHP versions and highlights the default; per-version PHP-FPM metrics shown.
    • PHP install flow now runs via its own playbook and configures PHP-FPM plus web server socket integration.
  • Chores

    • Playbooks and helpers added PHP detection, apt retry/lock handling, and reporting back results to the CLI.
  • Chore (cleanup)

    • Core server install playbook removed embedded PHP steps (moved to PHP install playbook).

@coderabbitai

coderabbitai Bot commented Nov 11, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Adds a standalone PHP install workflow (new CLI command and playbook), integrates multi-version PHP detection and per-version PHP-FPM metrics into server-info, removes PHP handling from the main server-install playbook, prepends playbook helpers to remote scripts, and registers the new command in the Symfony app.

Changes

Cohort / File(s) Summary
Console commands
app/Console/Server/ServerInstallCommand.php, app/Console/Server/ServerInstallPhpCommand.php, app/SymfonyApp.php
Added new server:install:php command (ServerInstallPhpCommand) with --server, --php-version, and --php-default options; ServerInstallCommand accepts PHP options and invokes installPhp() after server install; new command registered in SymfonyApp.
Server trait & flow
app/Traits/ServersTrait.php
Added `installPhp(ServerDTO $server, array $info): array
Playbooks — new PHP installer
playbooks/server-install-php.sh
New playbook that validates env vars, sets up distro-specific repos, installs PHP packages and FPM, configures sockets/status, optionally sets system default, updates Caddy, and emits YAML result (status, php_version, is_default, fpm_socket_path, tasks_completed).
Playbooks — server info
playbooks/server-info.sh
Added detect_php_versions() and detect_php_default(); changed get_php_fpm_metrics() to accept a PHP version argument; emits per-version php blocks and per-version FPM metrics in output YAML; detection runs early in main.
Playbooks — demo site
playbooks/demo-site.sh
Added detect_php_default() usage and replaced hardcoded PHP-FPM socket path with a dynamic path derived from detected PHP version; removed inlined permission helper usage.
Playbooks — server install
playbooks/server-install.sh
Removed all PHP installation/configuration and PHP fields from YAML output; PHP setup delegated to server-install-php.sh; cleaned PHP-related tasks and monitoring endpoints.
Playbooks helpers & trait
playbooks/helpers.sh, app/Traits/PlaybooksTrait.php
New playbooks/helpers.sh with run_cmd(), detect_php_default(), wait_for_dpkg_lock(), apt_get_with_retry(); PlaybooksTrait now prepends helpers into playbook scripts before remote execution.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant CLI as ServerInstallPhpCommand
    participant Trait as ServersTrait
    participant Playbook as server-install-php.sh
    participant Host as RemoteServer

    User->>CLI: run server:install:php --server --php-version [--php-default]
    CLI->>Trait: selectServer() / getServerInfo()
    Trait-->>CLI: ServerDTO + info
    CLI->>Trait: installPhp(server, info)
    note right of Trait `#DFF6E1`: prompt version choice / set-default
    Trait->>Playbook: exec playbook with env (DISTRO, PERMS, PHP_VERSION, SET_DEFAULT)
    rect rgb(220,240,255)
      Playbook->>Host: add repo / apt update
      Playbook->>Host: install php packages & fpm
      Playbook->>Host: configure php-fpm socket & status
      Playbook->>Host: set update-alternatives (if requested)
      Playbook->>Host: update caddy config & reload
      Playbook-->>Trait: YAML result (status, php_version, is_default, fpm_socket_path)
    end
    Trait-->>CLI: installation result
    CLI->>User: success/failure + command replay info
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • Focus review on:
    • playbooks/server-install-php.sh (distro repo logic, dpkg lock/retry, Caddy insertion).
    • playbooks/server-info.sh (output YAML shape changes and per-version metrics).
    • app/Traits/ServersTrait.php (new install flow, prompts, and return-value/exit-code semantics).
    • End-to-end propagation of php_version and php_default through CLI → trait → playbook and command replay.

Possibly related PRs

  • bigpixelrocket/deployer-php#64 — Overlapping changes to traits and console helpers; likely touches the same install/display wiring.
  • bigpixelrocket/deployer-php#62 — Prior work on server-info playbook/command; overlaps per-version detection and metrics logic.
  • bigpixelrocket/deployer-php#77 — Related modifications to ServersTrait and PHP/PHP-FPM display and metrics aggregation.

Poem

🐰
I hopped into the playbook glade,
Where PHP versions stack and braid,
Defaults blossom, sockets sing,
Caddy hums and services spring,
A rabbit’s patch of code well-made. 🥕

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 title accurately summarizes the main change: introducing a dedicated install-php playbook and corresponding command, which is the core theme across all modified files.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% 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/dedicated-install-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: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
playbooks/server-install.sh (1)

335-355: Remove stale PHP-FPM configuration logic.

This code block adds www-data to the deployer group and attempts to restart php8.4-fpm, but PHP installation has been moved to the separate server-install-php.sh playbook. At this point in execution, PHP may not be installed yet, causing this logic to either fail silently or reference non-existent services.

Apply this diff to remove the stale PHP-related configuration:

 	# Add www-data (PHP-FPM user) to deployer group so it can access files
-	if id -u www-data > /dev/null 2>&1; then
-		if ! id -nG www-data 2> /dev/null | grep -qw deployer; then
-			echo "✓ Adding www-data user to deployer group..."
-			if ! run_cmd usermod -aG deployer www-data; then
-				echo "Error: Failed to add www-data to deployer group" >&2
-				exit 1
-			fi
-
-			# Restart PHP-FPM so it picks up the new group membership
-			if systemctl is-active --quiet php8.4-fpm 2> /dev/null; then
-				echo "✓ Restarting PHP-FPM to apply group membership..."
-				if ! run_cmd systemctl restart php8.4-fpm; then
-					echo "Error: Failed to restart PHP-FPM" >&2
-					exit 1
-				fi
-			fi
-		fi
-	else
-		echo "Warning: PHP-FPM user 'www-data' not found, skipping group assignment"
-	fi
 }

Note: The www-data user group configuration should be handled in server-install-php.sh where PHP and PHP-FPM are actually installed.

playbooks/server-info.sh (1)

128-134: Extract duplicated helper functions to a shared module.

Multiple helper functions are duplicated across playbooks/server-info.sh, playbooks/demo-site.sh, playbooks/server-install.sh, and playbooks/server-install-php.sh:

  • run_cmd() - appears in all 4 playbooks with identical implementation
  • wait_for_dpkg_lock() - appears in server-install.sh and server-install-php.sh
  • apt_get_with_retry() - appears in server-install.sh and server-install-php.sh
  • detect_php_default() - appears in demo-site.sh and server-info.sh

Create a shared playbooks/helpers.sh file containing these common functions, then source it in each playbook:

#!/usr/bin/env bash
# playbooks/helpers.sh - Shared helper functions

# Permission Management
run_cmd() {
	if [[ $DEPLOYER_PERMS == 'root' ]]; then
		"$@"
	else
		sudo -n "$@"
	fi
}

# ... other shared functions

Then in each playbook:

# Source shared helpers
source "$(dirname "$0")/helpers.sh"

This eliminates duplication and ensures consistency across all playbooks.

Also applies to: 236-256

♻️ Duplicate comments (1)
playbooks/server-install-php.sh (1)

48-54: Consolidate duplicated helper functions.

The functions run_cmd(), wait_for_dpkg_lock(), and apt_get_with_retry() are duplicated across multiple playbooks. This has already been noted in the review of other files.

Refer to the comment on playbooks/server-info.sh for the recommended refactoring approach using a shared playbooks/helpers.sh file.

Also applies to: 63-93, 98-134

🧹 Nitpick comments (2)
app/Console/Server/ServerInstallPhpCommand.php (1)

74-82: Consider adding post-installation verification.

Unlike ServerInstallCommand which verifies the demo site via HTTP, this standalone PHP installation command doesn't verify that PHP-FPM is running and accessible. Consider adding a simple health check.

Example verification:

// After successful installation
$verification = $this->io->promptSpin(
    fn () => $this->verifyPhpFpm($server, $phpVersion),
    'Verifying PHP-FPM...'
);

if ($verification['status'] === 'success') {
    $this->yay($verification['message']);
}

Where verifyPhpFpm() could check the PHP-FPM status endpoint via Caddy proxy.

app/Traits/ServersTrait.php (1)

398-426: Extract hardcoded PHP versions to a class constant.

The list of PHP versions is hardcoded in the method body, making it harder to maintain and update when new PHP versions are released.

Apply this diff to extract to a constant:

+    /**
+     * Supported PHP versions for installation.
+     */
+    private const SUPPORTED_PHP_VERSIONS = ['5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3', '8.4', '8.5'];
+
     /**
      * Install PHP on a server.
      *
@@ -397,7 +400,6 @@
      */
     protected function installPhp(ServerDTO $server, array $info): array|int
     {
-        $phpVersions = ['5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3', '8.4', '8.5'];

         //
         // Extract installed PHP versions
@@ -419,7 +421,7 @@
         $phpVersion = (string) $this->io->getOptionOrPrompt(
             'php-version',
             fn () => $this->io->promptSelect(
                 label: 'PHP version:',
-                options: $phpVersions,
+                options: self::SUPPORTED_PHP_VERSIONS,
                 default: '8.4'
             )
         );
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2ba08b4 and f407e3d.

📒 Files selected for processing (8)
  • app/Console/Server/ServerInstallCommand.php (3 hunks)
  • app/Console/Server/ServerInstallPhpCommand.php (1 hunks)
  • app/SymfonyApp.php (2 hunks)
  • app/Traits/ServersTrait.php (2 hunks)
  • playbooks/demo-site.sh (2 hunks)
  • playbooks/server-info.sh (7 hunks)
  • playbooks/server-install-php.sh (1 hunks)
  • playbooks/server-install.sh (3 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/Console/Server/ServerInstallPhpCommand.php
  • app/SymfonyApp.php
  • app/Console/Server/ServerInstallCommand.php
🧠 Learnings (8)
📚 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 handle user interaction (input/output) and orchestrate Services

Applied to files:

  • app/Console/Server/ServerInstallPhpCommand.php
  • app/SymfonyApp.php
📚 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/**/@(Service|Services)/**/*.php : Extract complex orchestration shared by multiple Commands into dedicated Services

Applied to files:

  • app/Console/Server/ServerInstallPhpCommand.php
  • app/SymfonyApp.php
📚 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 : Only Commands perform console input/output operations

Applied to files:

  • app/Console/Server/ServerInstallPhpCommand.php
  • app/SymfonyApp.php
📚 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 are responsible for console styling, error formatting, and user prompts

Applied to files:

  • app/Console/Server/ServerInstallPhpCommand.php
  • app/SymfonyApp.php
📚 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/SymfonyApp.php
📚 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 receive Services via constructor injection

Applied to files:

  • app/SymfonyApp.php
📚 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 may only depend on Services (not other Commands)

Applied to files:

  • app/SymfonyApp.php
📚 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 contain business logic—delegate to Services

Applied to files:

  • app/SymfonyApp.php
🧬 Code graph analysis (6)
playbooks/server-install.sh (2)
playbooks/demo-site.sh (1)
  • run_cmd (37-43)
playbooks/server-info.sh (1)
  • run_cmd (129-135)
app/Traits/ServersTrait.php (4)
app/Services/IOService.php (3)
  • info (474-477)
  • displayDeets (543-566)
  • writeln (463-469)
app/DTOs/ServerDTO.php (1)
  • ServerDTO (7-19)
app/Traits/PlaybooksTrait.php (1)
  • executePlaybook (45-180)
app/Contracts/BaseCommand.php (1)
  • yay (175-179)
playbooks/server-info.sh (1)
playbooks/demo-site.sh (1)
  • detect_php_default (48-68)
app/Console/Server/ServerInstallPhpCommand.php (3)
app/Contracts/BaseCommand.php (3)
  • BaseCommand (29-242)
  • heading (166-170)
  • showCommandReplay (195-241)
app/Console/Server/ServerInstallCommand.php (1)
  • execute (44-176)
app/Traits/ServersTrait.php (3)
  • selectServer (525-563)
  • displayServerDeets (568-588)
  • installPhp (398-482)
playbooks/server-install-php.sh (3)
playbooks/demo-site.sh (1)
  • run_cmd (37-43)
playbooks/server-info.sh (1)
  • run_cmd (129-135)
app/Traits/PlaybooksTrait.php (1)
  • PlaybooksTrait (26-182)
app/Console/Server/ServerInstallCommand.php (1)
app/Traits/ServersTrait.php (1)
  • installPhp (398-482)
🔇 Additional comments (14)
app/SymfonyApp.php (1)

15-15: LGTM!

The new command is properly imported and registered following the existing pattern.

Also applies to: 148-148

app/Console/Server/ServerInstallCommand.php (2)

104-117: LGTM! PHP installation integrated correctly.

The PHP installation step is properly positioned after server installation and before demo site setup, which makes sense since the demo site requires PHP to function.


36-37: LGTM! Command options and replay data properly configured.

The new PHP-related options are correctly defined and propagated to the command replay, enabling non-interactive re-execution.

Also applies to: 169-173

playbooks/server-install.sh (1)

283-287: LGTM! Caddy localhost configuration prepared for PHP.

The placeholder comment correctly indicates that PHP-FPM status endpoints will be configured by the separate PHP installation playbook.

playbooks/demo-site.sh (1)

157-173: LGTM! Dynamic PHP-FPM socket path implementation.

The demo site now correctly detects the default PHP version and constructs the appropriate PHP-FPM socket path, supporting multi-version PHP installations.

playbooks/server-info.sh (1)

213-256: LGTM! Multi-version PHP detection and metrics.

The new functions properly detect installed PHP versions, identify the default version, and collect per-version PHP-FPM metrics, enabling comprehensive multi-version PHP support.

Also applies to: 376-425

app/Console/Server/ServerInstallPhpCommand.php (1)

42-95: LGTM! Command follows architectural patterns correctly.

The command properly orchestrates the PHP installation workflow by delegating to services and traits, handling errors appropriately, and providing command replay for automation. Based on learnings

app/Traits/ServersTrait.php (3)

241-273: LGTM! Multi-version PHP display with default marking.

The updated server info display correctly iterates through PHP versions and marks the default, with appropriate fallback messaging when no PHP is installed.


275-357: LGTM! Per-version PHP-FPM metrics display.

The implementation correctly displays PHP-FPM metrics for each installed PHP version, with proper type handling and conditional display for warning states (queue > 0, max_children_reached > 0, slow_requests > 0).


398-482: LGTM! PHP installation method properly extracts shared logic.

The installPhp() method correctly encapsulates PHP installation orchestration shared between ServerInstallCommand and ServerInstallPhpCommand, following the architectural pattern of extracting shared orchestration to traits. Based on learnings

playbooks/server-install-php.sh (4)

147-292: LGTM! PHP repository setup, installation, and configuration.

The playbook correctly handles distribution-specific repository setup (ondrej/php PPA for Ubuntu, Sury repository for Debian), installs PHP packages with appropriate extensions, configures PHP-FPM with proper socket permissions, and conditionally sets the PHP version as system default.


396-399: Verify PHP binary execution for version detection.

Line 398 executes php${DEPLOYER_PHP_VERSION} to get the actual installed version, but doesn't validate the binary exists first. If the installation succeeded but the binary is not in PATH, this will fall back to $DEPLOYER_PHP_VERSION.

Consider adding explicit binary existence check:

 	# Get actual PHP version
 	local php_version
-	php_version=$(php${DEPLOYER_PHP_VERSION} -r "echo PHP_VERSION;" 2> /dev/null || echo "$DEPLOYER_PHP_VERSION")
+	if command -v php${DEPLOYER_PHP_VERSION} > /dev/null 2>&1; then
+		php_version=$(php${DEPLOYER_PHP_VERSION} -r "echo PHP_VERSION;" 2> /dev/null || echo "$DEPLOYER_PHP_VERSION")
+	else
+		php_version="$DEPLOYER_PHP_VERSION"
+	fi

This makes the fallback behavior explicit and avoids executing a potentially non-existent command.


381-416: LGTM! Main orchestration and YAML output.

The main function correctly orchestrates all PHP installation steps in the right order and produces well-structured YAML output with all required fields.


301-375: No actionable issues found; the awk logic correctly handles config variations.

The test results demonstrate the script appropriately handles Caddy config structures:

  • Test 1 (empty server block): Handle block inserted before the final }
  • Test 2 (existing handle blocks): New block correctly appended before the server block's closing }
  • Test 3 (nested structures): Handle block inserted before the outermost }, not the inner nested closing braces

The awk pattern /^}$/ && !found only matches lines with an unindented closing brace, so indented braces within nested blocks (like the log { } section) are correctly ignored. This ensures insertion occurs at the server block boundary, not within nested structures. The code structure is sound for properly formatted Caddy configurations.

Comment thread playbooks/demo-site.sh Outdated
- Create playbooks/helpers.sh with 4 shared bash functions
- Update all playbooks to comment out source lines with explanation
- Modify executePlaybook() to automatically inline helpers.sh content
- Fix 'helpers.sh: No such file or directory' error on remote servers
- Reduce code duplication from ~200 lines to ~80 lines across playbooks

@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: 0

🧹 Nitpick comments (4)
playbooks/server-install.sh (1)

239-259: Consider moving PHP-FPM group configuration to the PHP installation playbook.

This code manages www-data (PHP-FPM user) group membership and service restart, but PHP installation has been moved to a separate playbook. Additionally, line 249 hardcodes php8.4-fpm, which won't work if other PHP versions are installed.

Consider:

  1. Moving this logic to server-install-php.sh where it can use DEPLOYER_PHP_VERSION
  2. Or removing it if it's only for backward compatibility with existing installations

If moving to server-install-php.sh, the code could be adapted:

-if systemctl is-active --quiet php8.4-fpm 2> /dev/null; then
+if systemctl is-active --quiet php${DEPLOYER_PHP_VERSION}-fpm 2> /dev/null; then
    echo "✓ Restarting PHP-FPM to apply group membership..."
-   if ! run_cmd systemctl restart php8.4-fpm; then
+   if ! run_cmd systemctl restart php${DEPLOYER_PHP_VERSION}-fpm; then
        echo "Error: Failed to restart PHP-FPM" >&2
        exit 1
    fi
fi
playbooks/server-info.sh (1)

462-501: Per-version metrics collection well implemented.

The loop correctly processes each detected PHP version and collects its FPM metrics independently. The YAML structure properly represents per-version data with quoted keys.

Minor suggestion: Consider using null instead of {} for the empty php_fpm section when no metrics are found, as it more clearly indicates absence of data.

Apply this diff if you prefer null for empty state:

-if ! echo "  {}" >> "$DEPLOYER_OUTPUT_FILE"; then
+if ! echo "  null" >> "$DEPLOYER_OUTPUT_FILE"; then
playbooks/server-install-php.sh (2)

205-279: Caddy configuration update has potential fragility.

The awk pattern at lines 252-258 inserts the handle block before the first } line it encounters. If localhost.caddy has multiple closing braces or a nested structure, this could insert in the wrong location.

Consider making the insertion more robust by:

  1. Looking for the specific closing brace of the http://localhost:9001 block
  2. Or using a more sophisticated parsing approach
  3. Or documenting that the localhost.caddy must follow a specific simple structure

Current pattern:

awk -v handle="$(cat "$temp_handle")" '
  /^}$/ && !found {
    print handle
    found=1
  }
  { print }
'

More robust pattern (matches last closing brace):

awk -v handle="$(cat "$temp_handle")" '
  /^}$/ { last_brace=NR; line[NR]=$0; next }
  { line[NR]=$0 }
  END {
    for(i=1; i<=NR; i++) {
      if(i==last_brace) print handle
      print line[i]
    }
  }
'

285-322: Main execution flow well structured.

The function properly orchestrates all installation tasks and collects final state. Getting the actual PHP version via the PHP binary (line 302) is a good validation step.

The tasks_completed list (lines 311-315) is static and includes all tasks even if some were skipped (e.g., set_as_default when DEPLOYER_PHP_SET_DEFAULT=false). Consider dynamically building this list to reflect only actually completed tasks:

local tasks_completed="- setup_php_repository\n  - install_php_packages\n  - configure_php_fpm"
[[ $DEPLOYER_PHP_SET_DEFAULT == 'true' ]] && tasks_completed+="\n  - set_as_default"
tasks_completed+="\n  - update_caddy_config"
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f407e3d and c8ec03c.

📒 Files selected for processing (6)
  • app/Traits/PlaybooksTrait.php (1 hunks)
  • playbooks/demo-site.sh (2 hunks)
  • playbooks/helpers.sh (1 hunks)
  • playbooks/server-info.sh (8 hunks)
  • playbooks/server-install-php.sh (1 hunks)
  • playbooks/server-install.sh (4 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/PlaybooksTrait.php
🔇 Additional comments (18)
app/Traits/PlaybooksTrait.php (1)

56-61: LGTM! Clean helper integration.

The prepending logic correctly checks for file existence before reading and integrates helpers seamlessly into the playbook execution flow. The outer try-catch block already handles any potential read exceptions.

playbooks/demo-site.sh (2)

30-31: Good documentation of auto-inlining mechanism.

The comment accurately describes how helpers are made available during remote execution, matching the implementation in PlaybooksTrait.php.


123-135: PHP version detection properly integrated.

The use of detect_php_default() from the shared helpers and the error handling when no PHP is found are both appropriate. The dynamic socket path correctly reflects the detected version.

playbooks/helpers.sh (4)

18-24: Clean permission wrapper implementation.

The function correctly uses "$@" to preserve argument boundaries and applies the appropriate privilege escalation based on DEPLOYER_PERMS.


33-53: Robust PHP version detection with fallback.

The two-tier approach (update-alternatives → direct binary check) provides good coverage. The regex patterns correctly extract version numbers.


97-133: Robust retry logic with smart error detection.

The function correctly distinguishes between lock-related errors (which warrant retry) and other errors (which fail fast). The exponential backoff and integration with wait_for_dpkg_lock provide good resilience against lock contention.


62-92: Verify fuser availability.

The function relies on fuser to detect lock file usage. Consider adding a check to ensure fuser is available, or document that it's a prerequisite.

Check if fuser is consistently available in the target environments (Ubuntu/Debian):

playbooks/server-install.sh (2)

39-40: Consistent helper integration documentation.

The commented source statement with explanatory note matches the pattern used across all playbooks.


187-191: Appropriate placeholder for PHP configuration.

The comment correctly indicates that PHP-FPM endpoints will be added by the dedicated PHP installation playbook, maintaining clear separation between server setup and PHP installation.

playbooks/server-info.sh (4)

29-31: Consistent helper integration.

The commented source statement maintains consistency with the helper auto-inlining mechanism used across all playbooks.


194-219: Clean multi-version PHP detection.

The function correctly identifies versioned PHP binaries, extracts version numbers with regex, sorts them properly, and returns a comma-separated list. The pattern php[0-9]* specifically targets versioned binaries while excluding the generic /usr/bin/php symlink.


339-350: Correct per-version metrics endpoint.

The function signature now accepts a PHP version parameter and correctly constructs version-specific endpoint URLs, aligning with the multi-version PHP support introduced in this PR.


444-446: PHP version information correctly structured.

The YAML output properly includes the detected PHP versions as an array and the default version, with appropriate handling for empty values.

playbooks/server-install-php.sh (5)

30-38: Comprehensive input validation.

All required environment variables are properly validated with clear error messages, and the commented source statement maintains consistency with the helper auto-inlining mechanism.


92-119: Comprehensive PHP package installation.

The function installs a well-rounded set of PHP extensions commonly needed for web applications. The use of --no-install-recommends and apt_get_with_retry ensures lean and resilient installation.


175-196: Default version setting looks correct.

The function properly uses update-alternatives --set for the main PHP binaries. The conditional execution based on DEPLOYER_PHP_SET_DEFAULT is appropriate.


51-83: Repository setup follows distribution best practices.

The function correctly uses the appropriate PHP repository for each distribution (ondrej/php PPA for Ubuntu, Sury repository for Debian) with proper GPG key handling.

Verify that lsb_release is available on target Debian systems, as it's required at line 75:


128-166: Verify sed patterns are idempotent.

The sed commands uncomment configuration lines (e.g., line 134: s/^;listen.owner = .*/listen.owner = caddy/). If these lines are already uncommented or have different values, the pattern might not match or could create duplicate entries.

Verify the FPM pool configuration state and whether sed patterns handle both commented and uncommented lines:

Consider using patterns that handle both cases:

sed -i 's/^;*listen.owner = .*/listen.owner = caddy/' "$pool_config"

…agement

- Move PHP-FPM user group configuration from server-install.sh to server-install-php.sh
- Implement marker-based Caddy localhost config management
- Improve separation of concerns between server and PHP installation playbooks

@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: 0

🧹 Nitpick comments (3)
playbooks/server-install.sh (2)

77-77: Update comment to reflect PHP removal from this script.

Line 77 comment still references PHP installation, but this function no longer installs PHP. The comment should reflect the actual packages being installed.

-# Install all required packages (Caddy, PHP, Git, system utilities)
+# Install all required packages (Caddy, Git, system utilities)

187-192: Clarify the placeholder marker intent in localhost.caddy.

The comment on line 189 references "PHP-FPM status endpoints" but the created file only contains a placeholder marker. While this design is sound (allowing the PHP install playbook to add endpoints), the comment could be more explicit about this being a placeholder.

-	# Create localhost.caddy - monitoring endpoints only accessible via localhost
-	# (PHP-FPM status endpoint will be added by PHP installation playbook)
+	# Create localhost.caddy - monitoring endpoints only accessible via localhost
+	# (PHP-FPM status endpoints will be added by PHP installation playbook via marker insertion)
playbooks/server-install-php.sh (1)

276-282: AWK script for marker-based config insertion works but could be more robust.

The AWK script inserts the multi-line $handle variable into localhost.caddy after the marker. While this should work, the approach with tabs and newlines embedded in a shell variable is somewhat fragile and could break if formatting changes.

Consider using a heredoc-based approach or writing the insertion more explicitly to improve robustness:

-	if ! awk -v handle="$(cat "$temp_handle")" '
-		/#### DEPLOYER-PHP CONFIG, WARRANTY VOID IF REMOVED :\) ####/ {
-			print
-			print handle
-			next
-		}
-		{ print }
-	' /etc/caddy/conf.d/localhost.caddy > "$temp_config"; then
+	if ! sed -e '/#### DEPLOYER-PHP CONFIG, WARRANTY VOID IF REMOVED :\) ####/r '"$temp_handle" \
+		/etc/caddy/conf.d/localhost.caddy > "$temp_config"; then

This uses sed with the r (read file) command, which is more idiomatic for inserting file contents after a marker.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c8ec03c and 84ca43e.

📒 Files selected for processing (2)
  • playbooks/server-install-php.sh (1 hunks)
  • playbooks/server-install.sh (4 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
playbooks/server-install.sh (1)
playbooks/helpers.sh (1)
  • run_cmd (18-24)
🔇 Additional comments (6)
playbooks/server-install-php.sh (5)

51-83: PHP repository setup logic is sound.

The distribution-specific repository configuration properly handles both Ubuntu (ondrej/php PPA) and Debian (Sury repository) with appropriate defensive checks to prevent duplicate additions. Error handling and conditional setup are correct.


128-197: PHP-FPM configuration and user group setup are correctly implemented.

Socket ownership configuration, status page enabling, service management, and user group membership changes are all properly guarded with systemctl checks and error handling. The pattern mirrors the server-install.sh approach for consistency.


206-227: Default version configuration correctly gates on DEPLOYER_PHP_SET_DEFAULT.

The set_as_default() function properly checks the environment variable before executing update-alternatives commands. The conditional logic correctly handles the true/false flag, and gracefully handles cases where update-alternatives might not be available.


236-304: Caddy configuration update has strong defensive checks and idempotency.

The function includes multiple safeguards: file existence check (line 237), idempotency verification (line 245 prevents duplicate endpoints), marker validation (line 251), and temporary file handling. The flow is safe and handles the expected marker structure from server-install.sh.


327-328: PHP version detection with fallback is good practice.

Line 328 queries the installed PHP binary for the actual version and falls back to the requested version if detection fails. This provides both verification that the correct version was installed and a sensible fallback, improving observability.

playbooks/server-install.sh (1)

39-40: No action required — PlaybooksTrait correctly implements helper prepending.

The verification confirms that PlaybooksTrait.php (lines 56-61) correctly prepends playbooks/helpers.sh contents to playbooks before remote execution. The helper functions (run_cmd, apt_get_with_retry) are available at runtime, and the commented-out source line in server-install.sh accurately documents this automatic inlining mechanism. The integration is working as intended.

@loadinglucian
loadinglucian merged commit ae2df2a into main Nov 11, 2025
5 checks passed
@loadinglucian
loadinglucian deleted the feat/dedicated-install-php branch November 11, 2025 14:16
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