Skip to content

Add site:pull: migrate a WordPress (or any) site between remote hosts#1

Merged
nbejansen merged 4 commits into
1.xfrom
feat/wp-pull
Jun 8, 2026
Merged

Add site:pull: migrate a WordPress (or any) site between remote hosts#1
nbejansen merged 4 commits into
1.xfrom
feat/wp-pull

Conversation

@nbejansen

@nbejansen nbejansen commented Jun 5, 2026

Copy link
Copy Markdown
Member

What

Replaces the original wp:pull (which mirrored a remote site onto the box running the tool) with site:pull, run from an admin's machine to migrate a site from a source host to a destination host.

# pilot.yml
sites:
  example:
    url: https://example.com
    host: web124.sitepilot.net
    user: bob
    path: ~/httpdocs
    source:
      host: 1.2.3.4
      user: alice
      path: /var/www/example
site:pull example        # or `site:pull` to pick interactively

How it works

  • Site selectionsites: map keyed by name; pick by argument or interactive picker.
  • WordPress detection — by wp-config.php on the source. WordPress → files and database; anything else → files only (works for non-WP apps too).
  • Direct transfers — rsync runs on the destination, pulling from the source over SSH agent forwarding; the file sync and DB dump never pass through the admin machine.
  • No WP-CLI required on the source — uses the source's own wp if present, otherwise pulls a fresh wp-cli.phar into a per-run temp dir; source commands run with --allow-root.
  • Credentials preserved — the destination keeps its own wp-config.php (valid DB creds/salts); only the table prefix is reconciled to the source's so the import resolves.
  • DB flow — export on source → destination pulls the dump → wp db import on destination → table-prefix reconcile → search-replace the URL → wp db optimize (always, as the final DB step, to reclaim space and refresh index statistics).
  • Output — Laravel Prompts: select/confirm, a progress bar with a live current-step hint, and a final summary of what was done. SSH uses BatchMode + 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. phpunit runs as APP_ENV=testing so Laravel Prompts use their console fallbacks, letting expectsChoice/expectsConfirmation drive select/confirm.

Operational notes

  • The admin SSHes to the destination with their agent forwarded (-A); the destination uses that key to reach the source — so the admin's key must be authorized on both.
  • Pulling a fresh wp-cli.phar needs outbound internet on the source (only when it has no wp).
  • Source & destination should share a table prefix convention, or rely on the automatic reconcile.

nbejansen and others added 2 commits June 5, 2026 22:26
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.
@nbejansen nbejansen changed the title Add wp:pull command to pull a remote WordPress site Add site:pull: migrate a WordPress (or any) site between remote hosts Jun 8, 2026
nbejansen added 2 commits June 8, 2026 20:59
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
@nbejansen nbejansen merged commit 11634ff into 1.x Jun 8, 2026
1 check passed
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