Skip to content

feat(cli): openctl plan — batch $ref dependency preview (K7)#151

Merged
astrojerms merged 1 commit into
mainfrom
feat/k7-plan
Jul 20, 2026
Merged

feat(cli): openctl plan — batch $ref dependency preview (K7)#151
astrojerms merged 1 commit into
mainfrom
feat/k7-plan

Conversation

@astrojerms

Copy link
Copy Markdown
Owner

K7 — batch plan-preview (openctl plan)

Adds openctl plan -f <files|dirs>: load a set of manifests and preview the apply order derived from their $ref markers — what will happen, in what order, and what waits on whatbefore any apply, with no controller connection.

$ openctl plan -f examples/homelab/
Plan: 11 resource(s), 2 wave(s)

Apply order:
  wave 1:
    Cluster/home
    Tunnel/home
  wave 2:
    DNSRecord/chat  ← Tunnel/home
    HelmRelease/ollama  ← Cluster/home
    Platform/home  ← Cluster/home
    ...

How

  • internal/plan — a pure package that builds the cross-resource dependency graph via the same refs.Collect primitive the dispatcher uses (keyed on the full apiVersion|kind|name triple, so same-Kind/Name across providers don't collide), topologically sorts it (Kahn) into waves — resources in a wave have no inter-dependency and can apply concurrently — records each node's direct deps and any $ref targets outside the set (must already exist), and errors on a dependency cycle naming the stuck resources.
  • internal/cli/plan.go — the command plus a batch loader that walks directories recursively and dispatches .cueLoadCUE, .yaml/.ymlLoadMultiple.

Verification

  • Validated live by planning the shipped examples/homelab/ set (11 resources → 2 waves).
  • Unit tests: chain / diamond / external-ref / cycle / duplicate-identity / same-Kind+Name-distinct-apiVersion / no-refs; the batch loader (dir walk, multi-doc YAML, unsupported ext, missing path); and rendered output.

Remaining (tracked in ROADMAP)

  • Per-resource dry-run --diff is server-only (needs the controller's DryRunApply: drift vs stored last-applied + live provider Get) — deferred.
  • A batch RPC to expose the same DAG to the UI.
  • Pairs with I1 (plan-on-PR: render this preview on a PR).

Local CI: build, go test ./... (+-race on plan), gofmt, vet, staticcheck, golangci-lint (0 issues), modernize — all green.

New `openctl plan -f <files|dirs>`: load a set of manifests and preview
the apply order derived from their $ref markers, before any apply and
with no controller connection.

- internal/plan: pure package that builds the cross-resource dependency
  graph via refs.Collect (keyed on the full apiVersion|kind|name triple),
  topologically sorts it (Kahn) into WAVES — resources in a wave have no
  inter-dependency and can apply concurrently — records each node's direct
  deps and any $ref targets outside the set (must already exist), and
  errors on a cycle (naming the stuck resources).
- internal/cli/plan.go: the command + a batch loader that walks dirs
  recursively and dispatches .cue → LoadCUE, .yaml/.yml → LoadMultiple.

Validated by planning the shipped examples/homelab/ set (11 resources →
2 waves: cluster+tunnel, then everything that $refs them).

Remaining (tracked): per-resource dry-run --diff is server-only (needs
the controller's DryRunApply), plus a batch RPC to expose the DAG to the
UI. Pairs with I1 (plan-on-PR).

Tests: chain/diamond/external-ref/cycle/duplicate/same-kind-name-distinct-
apiVersion/no-refs, plus the batch loader (dir walk, multi-doc, bad ext,
missing path) and rendered output.
@astrojerms
astrojerms merged commit 0ede2ff into main Jul 20, 2026
6 checks passed
@astrojerms
astrojerms deleted the feat/k7-plan branch July 20, 2026 01:01
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