Skip to content

Add sync/export/apply-dir commands to copy portable org state between instances - #13

Merged
andredlng merged 8 commits into
mainfrom
apply-command
Jul 17, 2026
Merged

Add sync/export/apply-dir commands to copy portable org state between instances#13
andredlng merged 8 commits into
mainfrom
apply-command

Conversation

@andredlng

@andredlng andredlng commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Depends on datamesh-manager/entropy-data#1521 — that app PR adds GET/PUT /api/organization/features, which this PR's organization-features resource requires (already merged to app main). It must be deployed before sync/apply dir can copy organization features to a target instance. The rest of this PR works against the current API.

Summary

Adds commands to copy an organization's portable, declarative state from one Entropy Data instance to another — e.g. promoting a test environment's setup to production.

entropy-data export dir <path>  -c <source>                                    # enumerate a source into a local YAML tree
entropy-data apply  dir <path>  -c <target> [--include] [--prune] [--dry-run]  # apply a tree into a target (kubectl-apply style)
entropy-data import zip <file>  -c <target> [--prune]                          # unchanged (app-produced export zip)
entropy-data sync --source <conn> --target <conn> --include a,b [--exclude] [--prune] [--dry-run] [--keep <dir>]
  • sync exports the source into a staged directory and applies it to the target in one step, producing an auditable, re-runnable transfer. --source and --target are both required. It copies nothing by default — the resources to copy must be named with --include, and a run without it exits non-zero listing the known resources. Supports --exclude, --prune, --dry-run (per-resource create/update/prune counts), and --keep <dir>.
  • export dir enumerates a source into a local YAML tree, mirroring the app's organization-export layout so artifacts interchange.
  • apply dir reconciles such a tree into the connected instance, in the spirit of kubectl apply -f <dir>. Uses a folder-as-kind convention: the folder name is the resource kind and each YAML file below it is one resource (addressed by the id in its body); files carry no kind: field, so the enclosing folder is authoritative and unknown folders are ignored. Applies the whole tree by default (the directory is the selection); --include/--exclude narrow it, --dry-run previews, --prune mirrors deletions. apply dir --help enumerates the recognized folder names.
  • import zip is unchanged (Simon's command); it now extracts to a temp dir and applies through the same engine.
  • Fix: the tree apply silently dropped sourcesystems/ from an org export — now applied in its correct dependency position (after policies, before assets).
  • Copies teams, tags, definitions, policies, sourcesystems, certifications, classification-schemes, assets, datacontracts, dataproducts, example-data, access, the semantics graph (namespace rows + one OSI ontology YAML document per namespace), and the organization feature configuration (singleton).

One shared resources.py/sync.py engine drives export, apply and sync so they cannot drift, with three resource shapes:

  • Flat/api/{path} list + /api/{path}/{id}; artifact <name>/<id>.yaml.
  • Document (semantics ontology) — one raw-YAML document per namespace, GET/PUT at .../{ns}/ontology.yaml; artifact <name>/<namespace>.yaml; the app imports the whole document in correct internal order (groups before members, concepts before relationships). Not pruned.
  • Singleton (organization-features) — one object at /api/{path} (no id, no list); artifact <name>/<name>.yaml; applied last so a restrictive managedTagsPolicy it carries cannot reject earlier writes; never pruned.

All writes are idempotent PUT-by-id (or PUT-to-path for the document/singleton); the run is continue-on-error with a per-resource summary and non-zero exit on any failure.

Discoverability

sync --help and apply dir --help both list the supported resource kinds (folder names), built from the single RESOURCE_ORDER source. sync without --include, or a bad --include, errors with the known-resource list.

Not synced

Users & team members, API keys, git credentials, integration/connector credentials, usage, costs, test results, events, and lineage (per-instance identity, secrets, or telemetry). Organization customization, SCIM mapping, team-roles config, notification channels, connectors, and integrations are not supported yet.

Testing

ruff check/ruff format clean; pytest — 278 passed (27 in the export/apply/sync suite, covering flat + document semantics + singleton export/apply/prune, upsert ordering, prune reverse-order + absent-only, sync orchestration, the --include-required guard, apply dir --help kind listing, and the sourcesystems fix). The only local failures are 3 pre-existing machine-specific truststore tests, green in CI.

Docs

Companion docs PR: entropy-data/entropy-data-docs#124 (environment-sync how-to + CLI reference, folder-as-kind layout, recognized folder names). The changelog links to the guide and the CLI reference Links section links back to the changelog.

Add a new `apply --source <conn> --to <conn>` command that copies an
organization's portable, declarative state from one Entropy Data
instance to another by exporting the source into a staged directory and
importing it into the target.

- New `export dir <path>` enumerates a source into a local YAML tree
  (one directory per resource, one file per resource by id), mirroring
  the app's organization-export layout.
- `import` gains an `import dir <path>` subcommand; `import zip` now
  extracts and reuses the same dir-import engine. Both gain --prune
  (reverse-dependency-order delete of resources absent from the import,
  confirmation-gated unless --yes) and --include/--exclude; `import dir`
  and `apply` also support --dry-run.
- Fix `import` silently dropping sourcesystems from an org export.
- export/import/apply now also copy certifications, classification-schemes
  and example-data. Writes are idempotent PUT-by-id, team members are
  stripped on import, asset tag assignments are replayed, and audit
  fields are stripped before PUT. The experimental semantics API is not
  yet included.

Resource ordering, identity fields and per-resource handling live in one
shared module so export, import and apply cannot drift.
@andredlng andredlng self-assigned this Jul 14, 2026
Extend the export/import/apply engine to handle nested (parent-
parameterized) resources and include the semantics graph:
semantic-namespaces (flat), and semantic-concepts / semantic-
relationships nested per namespace.

A nested Resource carries a parent name and a {parent} api_path
template. Export lists the parent, then children per parent, writing
<name>/<namespace>/<id>.yaml; import upserts namespace-first; prune
enumerates parents and removes absent children per namespace (in
reverse dependency order). Flat behavior is unchanged.
Add singleton resource support to the copy engine and include the
organization feature configuration (GET/PUT /api/organization/features)
as an org-level singleton with no id and no collection.

Export reads the object and writes organization-features/
organization-features.yaml (skipping when unset); import PUTs it back;
it is applied last so a restrictive policy it carries cannot reject
tag/asset imports running earlier, and it is never pruned.

Requires the app-side endpoint (entropy-data#1521), which must be
merged and deployed to the target instance before this resource can be
applied.
Replace the per-concept/relationship nested handling with a single
per-namespace ontology document, using the app's new
GET/PUT /api/semantics/experimental/namespaces/{ns}/ontology.yaml
endpoint. The app imports the document in the correct internal order
(groups before members, concepts before relationships), so the client
no longer needs any concept-ordering logic.

Add a 'document' resource shape (one raw-YAML document per parent,
artifact <name>/<parent>.yaml, not prunable) and drop the now-unused
nested-collection machinery. The namespace row is still copied first as
a normal resource.

Requires the app-side ontology.yaml endpoint (entropy-data#1524).
Rename the apply command to sync (--source/--target instead of
--source/--to, both required). sync now copies nothing by default: the
resources to copy must be named with --include, and a run without it
exits non-zero listing the known resources.

sync --help, the README, and the CHANGELOG now spell out which resources
are supported and which are not synced (per-instance identity, secrets,
telemetry) or not supported yet.
Move the directory path out of the import group into its own apply
command: 'apply dir <path>' reconciles a local export tree into the
connected instance, like 'kubectl apply -f <dir>'. Keep 'import zip'
as-is. Rename the shared engine primitives (import_dir -> apply_dir,
plan_import -> plan_apply) accordingly.

Document the folder-as-kind convention: the directory name is the
resource kind and each YAML file below it is one resource addressed by
its body id; files carry no kind: field, so the enclosing folder is
authoritative and unknown folders are ignored. 'apply dir' applies the
whole tree by default (the directory is the selection), unlike 'sync'
which requires --include.
@andredlng andredlng changed the title Add apply command to copy portable org state between instances Add sync/export/apply-dir commands to copy portable org state between instances Jul 17, 2026
Build the apply dir help text from RESOURCE_ORDER so the command that
consumes the directory tree also enumerates the valid folder names
(kinds), matching sync --help. Add a regression test.
@andredlng
andredlng merged commit cff1c70 into main Jul 17, 2026
5 checks 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