fix(kubernetes): single-file GitOps delivery and Kustomize metadata.name exemption - #2874
fix(kubernetes): single-file GitOps delivery and Kustomize metadata.name exemption#2874Erik Osterman (Cloud Posse) (osterman) wants to merge 5 commits into
Conversation
…e objects from metadata.name The `git` provision target always treated its configured `path` as a directory, fanning out one auto-named file per manifest even when the path named an exact file (e.g. `kustomization.yaml`) — creating a directory by that name instead. Kustomize's own `Kustomization`/`Component` objects were also rejected by Atmos's structural validator for lacking `metadata.name`, even though Kustomize's own schema (and its own field-enforcement checks) never requires one. - Add a `split` tri-state on git provision targets: explicit `true`/`false` wins, otherwise inferred from whether `path`'s last segment looks like a manifest filename. `split: false` merges rendered manifests into a single file at the exact path instead of a directory. - Exempt Kustomize's own `Kustomization`/`Component` kinds (matched against their own vendored `sigs.k8s.io/kustomize/api/types` constants) from the `metadata.name` presence check; add an explicit `validate: false` component flag as a general override for the apply/deploy auto-gate and the standalone `validate` command. - Document the new `split` and `validate` fields, and add a full walkthrough for generating a Kustomize component/patch for GitOps delivery.
Required release docs for the split/validate provision-target fix: a problem-first blog post walking through the Kustomize component/GitOps pattern, and a new shipped milestone on the Extensibility roadmap initiative (with a corrected progress percentage).
|
Tip Atmos Pro
No affected stacks workflow was detected for this pull request. |
Dependency Review✅ No vulnerabilities or license issues found.Scanned FilesNone |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (4)
🚧 Files skipped from review as they are similar to previous changes (4)
📝 WalkthroughWalkthroughThis change adds Kustomize-aware Kubernetes validation controls and optional validation bypass. Git targets now support inferred or explicit split mode, including deterministic single-file multi-document YAML output. Schemas, tests, and GitOps documentation describe the new options. ChangesKubernetes validation controls
Manifest delivery
GitOps workflow documentation
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant KubernetesRender
participant GitProvisionTarget
participant writeArtifact
participant MergeYAMLDocuments
participant GitRepository
KubernetesRender->>GitProvisionTarget: rendered artifacts
GitProvisionTarget->>writeArtifact: resolved split mode
writeArtifact->>MergeYAMLDocuments: sorted documents
MergeYAMLDocuments-->>writeArtifact: multi-document YAML
writeArtifact->>GitRepository: write target file or directory
Possibly related PRs
Suggested labels: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@pkg/component/kubernetes/executor.go`:
- Around line 261-265: Update the validation flow around
resolveComponentValidateEnabled, resolveValidateOptions, and runValidate so
validation options are resolved before the validate:false check and --server
requests still call runValidate against the live cluster. Restrict the skip
result to offline structural validation only, preserving existing behavior
otherwise, and add a regression test covering validate:false with --server.
In `@website/blog/2026-08-05-kustomize-gitops-delivery.mdx`:
- Around line 8-10: Update the Kustomize filename explanation in the blog
content to say that a remote base or component must contain a recognized
reserved kustomization file name, not only kustomization.yaml. Use Kustomize as
the context and mention the supported filenames kustomization.yaml,
kustomization.yml, and Kustomization, while keeping kustomization.yaml as the
example. Preserve the existing point that the name is fixed by Kustomize and not
configurable.
In `@website/docs/stacks/components/kubernetes.mdx`:
- Around line 239-244: Update the Kubernetes delivery-mode documentation near
the `path` and `split` explanation to state that an unset `split` infers
single-file delivery when `path` ends in `.yaml`, `.yml`, or `.json`; otherwise
it defaults to directory delivery. Clarify that users should set `split`
explicitly when they need to override this path-based inference.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 07caf576-d657-4dff-a351-701802edd092
📒 Files selected for processing (15)
pkg/component/kubernetes/executor.gopkg/component/kubernetes/executor_test.gopkg/component/kubernetes/render.gopkg/component/kubernetes/validate.gopkg/component/kubernetes/validate_test.gopkg/datafetcher/schema/stacks/stack-config/1.0.jsonpkg/provisioner/target/git/git.gopkg/provisioner/target/git/git_test.gopkg/provisioner/target/manifest.gopkg/provisioner/target/manifest_test.gowebsite/blog/2026-08-05-kustomize-gitops-delivery.mdxwebsite/docs/cli/commands/kubernetes/kubernetes-deploy.mdxwebsite/docs/cli/commands/kubernetes/kubernetes-validate.mdxwebsite/docs/stacks/components/kubernetes.mdxwebsite/src/data/roadmap.js
Address CodeRabbit review on #2874: - The validate:false short-circuit returned before resolving --server, so `atmos kubernetes validate --server` never reached the live cluster for a component with validate:false. Resolve validate options first and only skip the offline structural check; --server still runs runServerValidate. Adds a regression test. - Blog post overclaimed kustomization.yaml as the only recognized filename; Kustomize also accepts kustomization.yml and Kustomization (confirmed against the vendored dependency). - Applied CodeRabbit's suggested wording clarifying the split-unset path-extension inference in the stack config docs.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #2874 +/- ##
==========================================
+ Coverage 82.75% 82.77% +0.02%
==========================================
Files 1860 1862 +2
Lines 180337 180485 +148
==========================================
+ Hits 149240 149402 +162
+ Misses 23309 23295 -14
Partials 7788 7788
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
|
CodeRabbit (@coderabbitai) full review |
✅ Action performedFull review finished. |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
pkg/component/kubernetes/validate_test.go (1)
107-113: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winUse a table-driven test for validation-option resolution.
These assertions test five input scenarios. Put them in one table to follow the repository test convention.
As per coding guidelines, “Use table-driven tests for testing multiple scenarios in Go.”
Proposed refactor.
func TestResolveComponentValidateEnabled(t *testing.T) { - assert.True(t, resolveComponentValidateEnabled(nil), "unset defaults to enabled") - assert.True(t, resolveComponentValidateEnabled(map[string]any{}), "unset defaults to enabled") - assert.True(t, resolveComponentValidateEnabled(map[string]any{"validate": true})) - assert.False(t, resolveComponentValidateEnabled(map[string]any{"validate": false})) - assert.True(t, resolveComponentValidateEnabled(map[string]any{"validate": "false"}), "non-bool values are ignored, defaulting to enabled") + tests := []struct { + name string + componentSection map[string]any + want bool + }{ + {"nil defaults to enabled", nil, true}, + {"empty defaults to enabled", map[string]any{}, true}, + {"true enables validation", map[string]any{"validate": true}, true}, + {"false disables validation", map[string]any{"validate": false}, false}, + {"non-boolean defaults to enabled", map[string]any{"validate": "false"}, true}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, resolveComponentValidateEnabled(tt.componentSection)) + }) + } }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@pkg/component/kubernetes/validate_test.go` around lines 107 - 113, Refactor TestResolveComponentValidateEnabled into a table-driven test covering the existing five inputs and expected results, including descriptive case names and messages where useful. Iterate over the cases with the repository’s standard subtest pattern while preserving the current validation-option behavior assertions.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@website/blog/2026-08-05-kustomize-gitops-delivery.mdx`:
- Around line 57-58: Update
website/blog/2026-08-05-kustomize-gitops-delivery.mdx:57-58,
website/docs/stacks/components/kubernetes.mdx:270-271, and
pkg/provisioner/target/git/git_test.go:250-252 to use
kustomize.config.k8s.io/v1alpha1 for Component fixtures. Update
website/docs/cli/commands/kubernetes/kubernetes-validate.mdx:106-113 to document
Kustomization as v1beta1 and Component as v1alpha1 separately, removing the
wildcard API-version description.
---
Nitpick comments:
In `@pkg/component/kubernetes/validate_test.go`:
- Around line 107-113: Refactor TestResolveComponentValidateEnabled into a
table-driven test covering the existing five inputs and expected results,
including descriptive case names and messages where useful. Iterate over the
cases with the repository’s standard subtest pattern while preserving the
current validation-option behavior assertions.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 98b624ea-72ff-4b64-addf-5fbc73840f88
📒 Files selected for processing (15)
pkg/component/kubernetes/executor.gopkg/component/kubernetes/executor_test.gopkg/component/kubernetes/render.gopkg/component/kubernetes/validate.gopkg/component/kubernetes/validate_test.gopkg/datafetcher/schema/stacks/stack-config/1.0.jsonpkg/provisioner/target/git/git.gopkg/provisioner/target/git/git_test.gopkg/provisioner/target/manifest.gopkg/provisioner/target/manifest_test.gowebsite/blog/2026-08-05-kustomize-gitops-delivery.mdxwebsite/docs/cli/commands/kubernetes/kubernetes-deploy.mdxwebsite/docs/cli/commands/kubernetes/kubernetes-validate.mdxwebsite/docs/stacks/components/kubernetes.mdxwebsite/src/data/roadmap.js
… gap Address CodeRabbit full-review findings on #2874: - All Component examples/fixtures used kustomize.config.k8s.io/v1beta1, which is Kustomization's version, not Component's (v1alpha1). Since isKustomizeConfigObject matches exact (apiVersion, kind) pairs, the examples never actually got the metadata.name exemption they claimed. Fixed in the blog post, the kubernetes.mdx walkthrough, and test fixtures; kubernetes-validate.mdx now documents both exact pairs instead of a kustomize.config.k8s.io/* wildcard. - Added TestWriteArtifactSingleFileModeWriteFailure, closing the patch coverage gap Codecov flagged on writeSingleArtifactFile's two new error branches (MkdirAll/WriteFile failure), mirroring the existing split=true failure test.
what
kubernetes.gitops.provision.targets.<name>(kind: git) now supports asplittri-state:split: falsewritespathas a single merged multi-document YAML file instead of always treatingpathas a directory of auto-named files; unset infers the mode from whetherpath's last segment looks like a manifest filename (.yaml/.yml/.json).metadata.nameon Kustomize's ownKustomization/Componentobjects (matched againstsigs.k8s.io/kustomize/api/types's own kind/version constants), since Kustomize's own schema and field-enforcement never require one.validate: falsecomponent-level flag opts a component out of both the apply/deploy structural auto-gate and the standaloneatmos kubernetes validatecommand.splitdocumented onkubernetes-deploy.mdx, and the Kustomize exemption /validate: falsedocumented onkubernetes-validate.mdx.why
pathwas always treated as a directory, so configuringpath: ".../kustomization.yaml"created a directory by that name containing an auto-generated file inside it, instead of the exact file Kustomize's remote-include mechanism requires.metadata.nameunconditionally, forcing users to add a meaningless name to KustomizeComponent/Kustomizationobjects just to satisfy Atmos, even though Kustomize's own tooling never requires one.!terraform.state) and committing it to a deployment repo as a properkustomization.yamlfor Argo CD/Flux to consume.references
Summary by CodeRabbit
New Features
split, with automatic mode selection based on the destination path.KustomizationandComponentobjects no longer requiremetadata.name.validatesetting to bypass offline structural validation.Bug Fixes
Documentation