diff --git a/infra-tools/internal/renderdiff/engine.go b/infra-tools/internal/renderdiff/engine.go index 8d569bfd462..359a3c86044 100644 --- a/infra-tools/internal/renderdiff/engine.go +++ b/infra-tools/internal/renderdiff/engine.go @@ -159,8 +159,13 @@ func (e *Engine) buildPair(cd *ComponentDiff) error { cd.BaseYAML = baseYAML } - // If neither side has the directory, nothing to diff. + // If neither side produced output, check whether the directory exists. + // Empty-base overlays (resources: []) intentionally produce no output; + // treat them as a no-op instead of an error. if cd.HeadYAML == nil && cd.BaseYAML == nil { + if e.head.DirExists(cd.Path) || e.base.DirExists(cd.Path) { + return nil + } return fmt.Errorf("component %s does not exist on either ref", cd.Path) } diff --git a/infra-tools/internal/renderdiff/engine_test.go b/infra-tools/internal/renderdiff/engine_test.go index b37992539f8..b5b4b1ad2c8 100644 --- a/infra-tools/internal/renderdiff/engine_test.go +++ b/infra-tools/internal/renderdiff/engine_test.go @@ -226,6 +226,30 @@ func TestEngine_NoEffectiveChange(t *testing.T) { g.Expect(result.Diffs).To(BeEmpty()) // identical YAML → omitted } +func TestEngine_EmptyBase_NewComponent(t *testing.T) { + g := NewWithT(t) + + // Simulates an empty-base overlay (resources: []) that produces no output. + // The directory exists on HEAD but not on base, and BuildKustomization + // returns nil (empty kustomize output). This should be silently skipped. + head := &fakeBuilder{ + exist: map[string]bool{"components/foo/staging/empty-base": true}, + yamls: map[string][]byte{"components/foo/staging/empty-base": nil}, + } + base := &fakeBuilder{ + exist: map[string]bool{}, + } + + engine := NewEngine(head, base, 2) + affected := map[detector.Environment][]appset.ComponentPath{ + detector.Staging: {{Path: "components/foo/staging/empty-base"}}, + } + + result, err := engine.Run(context.Background(), affected) + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(result.Diffs).To(BeEmpty(), "empty-base with no output should be silently skipped") +} + func TestEngine_EmptyInput(t *testing.T) { g := NewWithT(t)