Skip to content

Add sync-local commands for local-server development#38

Open
jerico wants to merge 7 commits into
mainfrom
feature/stack-sync
Open

Add sync-local commands for local-server development#38
jerico wants to merge 7 commits into
mainfrom
feature/stack-sync

Conversation

@jerico
Copy link
Copy Markdown
Contributor

@jerico jerico commented May 4, 2026

Summary

  • Adds app sync-local database <app>, app sync-local uploads <app>, and app sync-local all <app> to pull remote Altis Dashboard backups into a local altis/local-server environment
  • Search-replace runs on the SQL stream via @automattic/vip-search-replace before import, configured under extra.altis.cloud.search-replace.<key> in composer.json (default key: local-server)
  • SSE backup progress streaming with a 10s poll fallback for fast backups that complete before the stream connects
  • Backup choice prompt lets the user reuse the latest existing backup or trigger a new one; --latest skips the prompt and auto-confirms
  • Post-sync hook (wp altis post-sync) is silently skipped if the command isn't registered
altis-cli stack sync database platform-test 
✔ Local project: /Users/hm/platform-test
Search-replace: 1 mapping(s) from composer.json[local-server]
✔ Use an existing backup or create a new one for platform-test? Use latest backup  platform-test-2026-05-04-12-44-43 · 24m old
✔ Import backup platform-test-2026-05-04-12-44-43 (24m old) and replace local DB? This cannot be undone. Yes
✔ Downloaded to /var/folders/27/7hk8l2mx6rv6x7k8ngz8ch5r0000gn/T/altis-sync-s6dYlT/platform-test.tar
✔ Extracted.
✔ Search-replace complete (1 mapping(s))
Success: Imported from '/usr/src/app/.altis-sync/database.sql'.
Database import complete.
Flushing object cache…
Warning: Flushing the cache may affect all sites in a multisite installation, depending on the implementation of the object cache.
Success: The cache was flushed.
Running wp altis post-sync…
✓ Database synced from platform-test

Partial sync — sync only the data you need:

  • --table (repeatable/comma-separated) filters the backup to specific tables
  • --site-id on database resolves multisite site IDs to their table names via the database-tables endpoint, then passes those as tables to the backup
  • --site-id on uploads maps to sites/{id}/ prefix
  • --site-id on all applies to both DB tables and uploads path (single value only — errors early if multiple given)
  • app sites <app> lists multisite site ID → domain mapping to help pick the right ID

Options

Flag Commands Description
--table database, all Table to include in partial backup. Repeatable; comma-separated.
--site-id all Multisite site ID. For database/all: resolves to table names. For uploads/all: maps to sites/{id}/ prefix.
--latest all Use latest existing backup without prompting (implies --yes)
--search-replace-key database, all Key under extra.altis.cloud.search-replace in composer.json (default: local-server)
--replace from=to database, all Explicit search-replace pair (repeatable)
--skip-search-replace database, all Skip search-replace step
--skip-post-sync database, all Skip wp altis post-sync
--dry-run-search-replace database, all Print resolved mappings and exit
--resume <logId> all Resume watching an existing backup task
--uploads-path uploads, all Uploads prefix to export from the remote app
--keep-archive all Keep downloaded archive after restore
--yes all Skip confirmation prompts
--debug all Log raw SSE events

Example usage

# Full database sync
altis-cli app sync-local database example-dev-01

# Partial: specific tables
altis-cli app sync-local database example-dev-01 --table=wp_posts --table=wp_comments

# Partial: all tables for a multisite site
altis-cli app sync-local database example-dev-01 --site-id=7

# Find site IDs first
altis-cli app sites example-dev-01

# Uploads for a specific multisite site
altis-cli app sync-local uploads example-dev-01 --site-id=7

Test plan

  • app sync-local database <app> — new backup, stream progress, import with search-replace, cache flush, post-sync
  • app sync-local database <app> --latest — no prompt, no confirm, uses latest backup
  • app sync-local uploads <app>
  • app sync-local all <app>
  • --table filters backup to specific tables
  • --site-id on database resolves to correct table names
  • --site-id on uploads maps to sites/{id}/ prefix
  • Multiple --site-id on uploads or all errors before backup starts
  • --dry-run-search-replace exits before validation
  • app sites <app> lists site ID → domain mapping

🤖 Generated with Claude Code

jerico and others added 2 commits May 4, 2026 21:08
Adds `altis-cli stack sync database <app>`, `stack sync uploads <app>`,
and `stack sync all <app>` to pull remote Vantage backups into a local
altis/local-server environment.

Key features:
- Choose between an existing backup or triggering a new remote backup
- SSE stream for live backup progress with 10s poll fallback to handle
  fast backups that complete before the stream connects
- Search-replace on the SQL stream via @automattic/vip-search-replace
  before import, configured under extra.altis.cloud.search-replace in
  composer.json (default key: local-server)
- Uploads extracted directly to content/uploads/ then synced into the
  local-server S3 bucket via composer server s3 import-uploads
- Cache flush and optional wp altis post-sync hook after DB import;
  post-sync is silently skipped if the command is not registered
- --dry-run-search-replace, --skip-search-replace, --skip-post-sync,
  --resume, --keep-archive, --yes, --debug, --json options

Also fixes lib/stream.js which was calling got.default.stream() —
got.default is undefined in got v14 ESM, so SSE streaming was silently
broken. Fixed to got.stream().

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
--latest uses the most recent existing backup without prompting and
implies --yes, making it suitable for scripted or repeated syncs.
Errors if no backup exists for the app.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@jerico jerico changed the base branch from main to add-vantage-api-coverage May 4, 2026 13:16
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@joehoyle
Copy link
Copy Markdown
Member

joehoyle commented May 4, 2026

I'd vote for more like "import-local" or "sync-local" as most things are by default in cloud, so sync could indicate that it is between cloud environments

Base automatically changed from add-vantage-api-coverage to main May 4, 2026 14:20
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@joehoyle joehoyle mentioned this pull request May 4, 2026
5 tasks
- Replace --tables with --table (repeatable array, comma-separated)
- Add --site-id to database and all: resolves multisite site IDs to
  table names via the database-tables endpoint before backup
- Add --site-id to uploads: maps to sites/{id}/ uploads path prefix
- Error early on multiple --site-id for uploads and all commands
- Warn when --site-id is passed with --latest or --resume
- Add app sites command to list multisite site ID → domain mapping

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@jerico jerico changed the title Add stack sync commands for local-server development Add sync-local commands for local-server development May 4, 2026
@jerico jerico changed the title Add sync-local commands for local-server development Add app sync-local commands for local-server development May 4, 2026
@jerico jerico changed the title Add app sync-local commands for local-server development Add sync-local commands for local-server development May 4, 2026
Comment thread lib/commands/stack/sync/uploads.js Outdated
Site ID 1 uses the base table prefix (wp_posts etc.) and stores uploads
at the root, not sites/1/. Syncing all data when site ID 1 is given and
noting this to the user.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Comment thread lib/commands/stack/sync/database.js Outdated
Only applies to uploads where sites/1/ doesn't exist.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@joehoyle
Copy link
Copy Markdown
Member

joehoyle commented May 6, 2026

@jerico if I run sync-local database --site-id 2 <stack> it asks me if I want to use latest, or create a new one. However, the latest backup isn't for site-id 2. It then downloads the full db backup and imports it. I'd expect either:

  1. It looks for latest backup just for that site (not sure if possible)
  2. It doesn't let me chose latest when I'm specifying a site id (or table)
  3. It downloads the full backup and only selects the table / id I'd chosen.

Does that make sense?

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.

2 participants