orbital migrate apply
orbital migrate apply is the second step in a migration. It consumes the JSON plan envelope produced by orbital migrate plan, provisions an OrbitalReg project + repositories that mirror the source registry, and writes a migration_runs row so a crashed apply can be resumed where it left off.
The CLI is a thin layer over POST /api/admin/migrate/apply. The strategy you supplied to plan (or the recommendation it picked) becomes the default; override with --strategy if you've decided differently.
Strategy semantics
| Strategy | What apply does |
|---|---|
big-bang | Creates the OrbitalReg project and local-mode repos. Artifact ingest follows in Phase E (importer-plugin glue). |
blue-green | Same as big-bang for the apply step — repos are local-mode placeholders. The cutover dance lives outside the CLI. |
lazy-proxy | Creates remote-mode repos with the source registry as the upstream. No bulk copy; consumer pulls fill the cache. Run orbital migrate finalize once the hit rate is steady. |
big-bang and blue-green are identical at the apply layer — the difference shows up at cutover time, not provisioning time.
Quick start
# 1. Generate a plan (Phase A)
orbital migrate plan \
--source jfrog \
--endpoint https://jfrog.example.com \
--token "$JFROG_TOKEN" \
--output-file migration-plan.json
# 2. Preview what apply would do (no writes)
orbital migrate apply --plan migration-plan.json --dry-run
# 3. Run it for real
orbital migrate apply --plan migration-plan.jsonSample output (pretty-printed):
Migration apply — strategy=big-bang project=jfrog-import
Run ID: 7f4a2d1c-9b1e-4e1c-95d8-2a4d05fe1c33
Status: complete
Provisioned: 42 repositor(y|ies)
Skipped: 3
- oddball-format-1 — unsupported format: oddballfmt
- existing-collision — repository jfrog-import/existing-collision already exists
- bad/key — repo key normalises to empty slug
Repositories:
- jfrog-import/maven-prod [maven, local]
- jfrog-import/npm-mirror [npm, local]
...
Next steps:
- Repos are local-mode placeholders; artifact ingest lands in Phase E.Flags
| Flag | Default | Notes |
|---|---|---|
--plan | (required) | Path to the JSON envelope migrate plan --output-file wrote. |
--strategy | plan's recommendation | Override: big-bang, blue-green, lazy-proxy. |
--project-slug | <source>-import | OrbitalReg project the new repos land under. |
--dry-run | false | Preview — no projects / repositories rows written. |
--resume | false | Continue a previously-failed apply for the same source/endpoint/project tuple. |
--json | false | Emit the full apply-result JSON instead of the pretty summary. |
Resuming a failed apply
If the server, your laptop, or the network blinks mid-apply, re-run with --resume. The server looks up the previous migration_runs row by (source, endpoint, project_slug, status='applying'), re-uses its progress_json, and skips repositories already provisioned in the prior attempt. Idempotency holds at the (project, slug) level — a re-creation of the same slug surfaces as a Skipped row with reason "repository … already exists".
orbital migrate apply --plan migration-plan.json --resume--resume and --dry-run are mutually compatible; combining them re-reads the plan and reports what work the resume would perform without writing.
What gets skipped
Apply is conservative. It records, but does not fail on:
- Unsupported format — a source repo whose
package_typedoesn't map to a registered OrbitalReg format. The row appears underSkippedwith reasonunsupported format: …. - Empty slug — a source key that normalises to an empty OrbitalReg slug (e.g.
::::or all-symbol keys). - Existing collision — an OrbitalReg repository at the target slug already exists. Apply doesn't overwrite. Drop / rename and re-run with
--resumeto retry.
Provisioned counts repos that landed; Skipped counts the above. The two together cover every plan repo.
Output formats
| Mode | Flag | Use case |
|---|---|---|
| Pretty | (default) | Operator review in a terminal |
| JSON | --json | Machine-readable for CI scripting + dashboards |
Exit codes
| Code | Meaning |
|---|---|
| 0 | Apply completed successfully (provisioned + skipped accounted for) |
| 1 | User error (bad flag, missing --plan, OrbitalReg returned 400) |
| 2 | Auth error (no OrbitalReg token, OrbitalReg returned 401 / 403) |
| 3 | Server error (OrbitalReg returned 5xx; the run row is left at failed so --resume works) |
Inspecting runs
GET /api/admin/migrate/runs returns the most recent runs (limit 50). GET /api/admin/migrate/runs/{id} returns one row including the full plan envelope and progress map. Useful for an admin UI that surfaces apply history; the CLI presents the same shape via --json.
What apply does not do
- Artifact ingest. Phase B leaves big-bang / blue-green repos empty. The per-source artifact walk lives in Phase E (importer plugins).
- Cutover automation. Pointing your CI at the new registry, port flips on a load balancer, or DNS changes — those are operator steps documented in the per-source playbooks.
- Verification.
orbital migrate verify(Phase C) compares artifact digests post-apply.