|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. |
| 4 | + |
| 5 | +## Project Overview |
| 6 | + |
| 7 | +FTP Deployment is a PHP CLI tool for automated deployment of web applications to FTP/SFTP servers. It intelligently synchronizes local and remote files, uploading only changed files and optionally deleting removed files. The tool supports preprocessing (JS/CSS minification), pre/post deployment hooks, and transactional-like uploads. |
| 8 | + |
| 9 | +## Core Architecture |
| 10 | + |
| 11 | +### Main Components |
| 12 | + |
| 13 | +**Deployer** (`src/Deployment/Deployer.php`) |
| 14 | +- Core synchronization engine that compares local and remote file states |
| 15 | +- Manages the deployment lifecycle: scanning → comparing → uploading → renaming → cleanup |
| 16 | +- Maintains `.htdeployment` file on server with MD5 hashes for incremental sync |
| 17 | +- Uses temporary `.deploytmp` suffix during upload for transactional-like behavior |
| 18 | + |
| 19 | +**Server Interface** (`src/Deployment/Server.php`) |
| 20 | +- Abstract interface for all server types (FTP, SFTP, local filesystem) |
| 21 | +- Implementations: `FtpServer`, `SshServer`, `PhpsecServer`, `FileServer` |
| 22 | +- `SshServer` requires ext-ssh2; `PhpsecServer` uses phpseclib for pure PHP SSH |
| 23 | +- `RetryServer` wraps any server implementation with automatic retry logic |
| 24 | + |
| 25 | +**JobRunner** (`src/Deployment/JobRunner.php`) |
| 26 | +- Executes pre/post deployment jobs (local shell commands, remote commands, HTTP callbacks) |
| 27 | +- Supports job types: `local:`, `remote:`, `upload:`, and `http://` |
| 28 | +- Can also execute PHP callables passed from config |
| 29 | + |
| 30 | +**Preprocessor** (`src/Deployment/Preprocessor.php`) |
| 31 | +- Minifies CSS (via clean-css) and JS (via uglifyjs) files |
| 32 | +- Expands Apache mod_include directives (`<!--#include file="..." -->`) |
| 33 | +- Requires Node.js tools installed globally |
| 34 | + |
| 35 | +**CommandLine** (`src/Deployment/CommandLine.php`) |
| 36 | +- Parses configuration files (both `.ini` and `.php` formats) |
| 37 | +- Sets up the Deployer with all configuration options |
| 38 | + |
| 39 | +**CliRunner** (`src/Deployment/CliRunner.php`) |
| 40 | +- Entry point for the CLI tool |
| 41 | +- Handles command-line arguments and orchestrates the deployment process |
| 42 | + |
| 43 | +### Key Mechanisms |
| 44 | + |
| 45 | +**Incremental Sync via Hash File** |
| 46 | +- `.htdeployment` file stores MD5 hashes of all deployed files |
| 47 | +- On each deployment, compares local file hashes against this file |
| 48 | +- Only uploads changed/new files and deletes removed files (if `allowDelete=true`) |
| 49 | + |
| 50 | +**Transactional Upload Pattern** |
| 51 | +- Files uploaded with `.deploytmp` suffix |
| 52 | +- All files renamed simultaneously after successful upload |
| 53 | +- Minimizes window where site has inconsistent state |
| 54 | + |
| 55 | +**Mask Matching** (`Helpers::matchMask()`) |
| 56 | +- Custom implementation similar to `.gitignore` syntax |
| 57 | +- Supports: wildcards `*`, character classes `[xy]`, negation `!`, path anchoring `/` |
| 58 | +- Used for both `ignore` and `include` configuration directives |
| 59 | + |
| 60 | +## Development Commands |
| 61 | + |
| 62 | +### Testing |
| 63 | + |
| 64 | +```bash |
| 65 | +# Run all tests |
| 66 | +vendor/bin/tester tests -s -C |
| 67 | + |
| 68 | +# Run specific test file |
| 69 | +vendor/bin/tester tests/Helpers.matchMask.phpt -s -C |
| 70 | + |
| 71 | +# Run tests with colors (-C) and show skipped tests (-s) |
| 72 | +vendor/bin/tester tests -s -C |
| 73 | +``` |
| 74 | + |
| 75 | +Tests use Nette Tester with `.phpt` format. The `test()` helper function is defined in `tests/bootstrap.php`. |
| 76 | + |
| 77 | +### Static Analysis |
| 78 | + |
| 79 | +```bash |
| 80 | +# Run PHPStan (informative only - not blocking) |
| 81 | +composer phpstan |
| 82 | +``` |
| 83 | + |
| 84 | +Note: PHPStan is configured to be non-blocking (continue-on-error in CI). |
| 85 | + |
| 86 | +### Running Deployment |
| 87 | + |
| 88 | +```bash |
| 89 | +# Run deployment with config file |
| 90 | +php deployment deployment.ini |
| 91 | + |
| 92 | +# Test mode (dry-run, no actual changes) |
| 93 | +php deployment deployment.ini --test |
| 94 | + |
| 95 | +# Or use the created PHAR |
| 96 | +php create-phar/deployment.phar deployment.ini |
| 97 | +``` |
| 98 | + |
| 99 | +### Building PHAR |
| 100 | + |
| 101 | +```bash |
| 102 | +# Build single-file executable |
| 103 | +php create-phar/create-phar.php |
| 104 | +``` |
| 105 | + |
| 106 | +Creates `create-phar/deployment.phar` which can be distributed as standalone tool. |
| 107 | + |
| 108 | +## Configuration |
| 109 | + |
| 110 | +Supports both `.ini` and `.php` config formats: |
| 111 | + |
| 112 | +**INI Format** (`deployment.sample.ini`) |
| 113 | +- Standard INI sections for multiple deployment targets |
| 114 | +- String-based job definitions |
| 115 | + |
| 116 | +**PHP Format** (`deployment.sample.php`) |
| 117 | +- Returns associative array |
| 118 | +- Can use PHP callables for `before`/`after`/`afterUpload` hooks |
| 119 | +- Callable signature: `function(Server $server, Logger $logger, Deployer $deployer)` |
| 120 | + |
| 121 | +## Coding Conventions |
| 122 | + |
| 123 | +- PHP 8.0+ required, all files must have `declare(strict_types=1)` |
| 124 | +- Uses tabs for indentation (per user's global CLAUDE.md preferences) |
| 125 | +- Follows Nette Coding Standard (PSR-12 based) |
| 126 | +- Namespace: `Deployment\` |
| 127 | +- Sensitive parameters marked with `#[\SensitiveParameter]` attribute |
| 128 | + |
| 129 | +## PHP Extensions |
| 130 | + |
| 131 | +**Required:** |
| 132 | +- `ext-zlib` - for gzip compression |
| 133 | + |
| 134 | +**Optional (protocol-dependent):** |
| 135 | +- `ext-ftp` - for `ftp://` and `ftps://` protocols |
| 136 | +- `ext-openssl` - for `ftps://` protocol |
| 137 | +- `ext-ssh2` - for `sftp://` protocol using native SSH2 |
| 138 | +- `ext-json` - for CSS preprocessing via online services |
| 139 | + |
| 140 | +If `ext-ssh2` is not available, use `phpsec://` protocol which uses phpseclib (pure PHP implementation). |
| 141 | + |
| 142 | +## Testing Philosophy |
| 143 | + |
| 144 | +- Unit tests for utility functions (`Helpers.*`) |
| 145 | +- Focused tests using `Assert::*` from Nette Tester |
| 146 | +- Test fixtures in `tests/fixtures/` |
| 147 | +- Temporary files in `tests/tmp/` (auto-cleaned) |
| 148 | + |
| 149 | +## Common Workflows |
| 150 | + |
| 151 | +### Adding New Server Type |
| 152 | + |
| 153 | +1. Create class implementing `Server` interface |
| 154 | +2. Add protocol parsing in `CommandLine::createServer()` |
| 155 | +3. Add protocol to README examples |
| 156 | + |
| 157 | +### Adding New Preprocessor |
| 158 | + |
| 159 | +1. Add method to `Preprocessor` class (e.g., `compressXxx()`) |
| 160 | +2. Register in `Deployer::collectPaths()` based on file extension |
| 161 | +3. Update default masks in `CommandLine::loadConfig()` |
| 162 | + |
| 163 | +### Modifying Job Types |
| 164 | + |
| 165 | +Job types are handled in `JobRunner`: |
| 166 | +- `local:` → `JobRunner::local()` (executes via PHP `exec()`) |
| 167 | +- `remote:` → `JobRunner::remote()` (parses and executes via Server interface) |
| 168 | +- `upload:` → `JobRunner::upload()` (uploads single file) |
| 169 | +- `http://` → `Helpers::fetchUrl()` (HTTP callback) |
0 commit comments