Add site:pull: migrate a WordPress (or any) site between remote hosts#1
Merged
Conversation
Reads pilot.yml (path, url, remote host/port/user/path) and pulls a remote WordPress site down to the local path: exports the remote DB via WP-CLI over SSH (streamed to a temp file), rsyncs the files (mirroring with --delete), imports the DB locally, and rewrites the site URL via search-replace if it differs from the configured url. - Config: loads + validates pilot.yml against caller-supplied rules, using Laravel's bundled validation messages - Site: typed value object + schema (RULES); path defaults to httpdocs and remote.port to 22 - WpCli / Rsync: thin Illuminate Process wrappers - InvalidConfig: carries validation errors for bullet-list rendering - Progress bar over the pull steps; temp dump cleaned up in finally - Pest tests + fixtures Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The toolkit now runs on an admin's machine and orchestrates a migration from a source host to a destination host, instead of pulling onto the local box. - site:pull [site] reads a `sites:` map from pilot.yml (each entry: the destination connection + url, plus a nested `source:`), selectable by key or via an interactive picker. - WordPress is detected by wp-config.php on the source. WordPress sites get a full DB migration; anything else is a files-only sync, so it works for other app types too. - Bulk data moves source <-> destination directly over SSH agent forwarding (rsync runs on the destination); nothing is proxied through the admin machine. - The source needs no WP-CLI: its own `wp` is used when present, otherwise a fresh wp-cli.phar is pulled into a per-run temp dir; source commands use --allow-root. - The destination keeps its own wp-config.php (valid DB credentials); only the table prefix is reconciled to the source's so the import resolves. - Output uses Laravel Prompts (select/confirm/progress with a live step hint, plus a summary); SSH calls use BatchMode + ConnectTimeout. Services split into Remote, Migration, Ssh, Rsync, WpCli (destination) and RemoteWpCli (source). Full Pest coverage; phpunit runs as APP_ENV=testing so prompt fallbacks drive expectsChoice/expectsConfirmation.
Always run `wp db optimize` on the destination after the import, table-prefix reconcile and search-replace, to reclaim space and refresh index statistics. Skipped for files-only (non-WordPress) pulls.
# Conflicts: # composer.json # composer.lock
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Replaces the original
wp:pull(which mirrored a remote site onto the box running the tool) withsite:pull, run from an admin's machine to migrate a site from a source host to a destination host.How it works
sites:map keyed by name; pick by argument or interactive picker.wp-config.phpon the source. WordPress → files and database; anything else → files only (works for non-WP apps too).wpif present, otherwise pulls a freshwp-cli.pharinto a per-run temp dir; source commands run with--allow-root.wp-config.php(valid DB creds/salts); only the table prefix is reconciled to the source's so the import resolves.wp db importon destination → table-prefix reconcile → search-replace the URL →wp db optimize(always, as the final DB step, to reclaim space and refresh index statistics).select/confirm, aprogressbar with a live current-step hint, and a final summary of what was done. SSH usesBatchMode+ConnectTimeout.Structure
Remote(one host),Migration(a site's source/destination/url + validation rules),Ssh,Rsync,WpCli(destination WP-CLI),RemoteWpCli(source WP-CLI, provisioned on demand).Tests
Full Pest coverage (72 tests) with
Process::fake.phpunitruns asAPP_ENV=testingso Laravel Prompts use their console fallbacks, lettingexpectsChoice/expectsConfirmationdriveselect/confirm.Operational notes
-A); the destination uses that key to reach the source — so the admin's key must be authorized on both.wp-cli.pharneeds outbound internet on the source (only when it has nowp).