Add sync/export/apply-dir commands to copy portable org state between instances - #13
Merged
Conversation
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.
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.
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.
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.
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.
syncexports the source into a staged directory and applies it to the target in one step, producing an auditable, re-runnable transfer.--sourceand--targetare 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 direnumerates a source into a local YAML tree, mirroring the app's organization-export layout so artifacts interchange.apply dirreconciles such a tree into the connected instance, in the spirit ofkubectl 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 nokind:field, so the enclosing folder is authoritative and unknown folders are ignored. Applies the whole tree by default (the directory is the selection);--include/--excludenarrow it,--dry-runpreviews,--prunemirrors deletions.apply dir --helpenumerates the recognized folder names.import zipis unchanged (Simon's command); it now extracts to a temp dir and applies through the same engine.sourcesystems/from an org export — now applied in its correct dependency position (after policies, before assets).One shared
resources.py/sync.pyengine drivesexport,applyandsyncso they cannot drift, with three resource shapes:/api/{path}list +/api/{path}/{id}; artifact<name>/<id>.yaml..../{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./api/{path}(no id, no list); artifact<name>/<name>.yaml; applied last so a restrictivemanagedTagsPolicyit 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 --helpandapply dir --helpboth list the supported resource kinds (folder names), built from the singleRESOURCE_ORDERsource.syncwithout--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 formatclean;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,syncorchestration, the--include-required guard,apply dir --helpkind 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.