Repository: GoogleContainerTools/kpt
Pull request #2376 (2021-07-09 00:56:10)

Remove default formatting, preserve field order and indentation
This Pr is to remove default formatting as part of render and eval commands, preserve field order and sequence indentation of resources.

Should be merged after https://github.com/kubernetes-sigs/kustomize/pull/4043

phanimarupaka: TODOs: 
Kyaml converts multiline scalars to single lines. This is due to go-yaml upgrade. @natasha41575 is working on fixing it. https://github.com/kubernetes-sigs/kustomize/issues/4066

Patch:
diff --git a/go.mod b/go.mod
index 142effa6..8ae7226d 100644
--- a/go.mod
+++ b/go.mod
@@ -13,7 +13,6 @@ require (
 	github.com/spf13/pflag v1.0.5
 	github.com/stretchr/testify v1.7.0
 	github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca
-	gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
 	gotest.tools v2.2.0+incompatible
 	k8s.io/apiextensions-apiserver v0.21.1
 	k8s.io/apimachinery v0.21.1
@@ -23,5 +22,5 @@ require (
 	k8s.io/kubectl v0.21.1
 	sigs.k8s.io/cli-utils v0.25.1-0.20210603052138-670dee18a123
 	sigs.k8s.io/kustomize/api v0.8.10 // indirect
-	sigs.k8s.io/kustomize/kyaml v0.10.22-0.20210614195535-7e8ba62e9fd9
+	sigs.k8s.io/kustomize/kyaml v0.11.1-0.20210715170645-339e33d2f33d
 )
diff --git a/go.sum b/go.sum
index f77abfda..12f0f0b7 100644
--- a/go.sum
+++ b/go.sum
@@ -931,6 +931,7 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
 gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
 gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
@@ -992,8 +993,8 @@ sigs.k8s.io/kustomize/cmd/config v0.9.10/go.mod h1:Mrby0WnRH7hA6OwOYnYpfpiY0WJIM
 sigs.k8s.io/kustomize/kustomize/v4 v4.1.2/go.mod h1:PxBvo4WGYlCLeRPL+ziT64wBXqbgfcalOS/SXa/tcyo=
 sigs.k8s.io/kustomize/kyaml v0.10.17/go.mod h1:mlQFagmkm1P+W4lZJbJ/yaxMd8PqMRSC4cPcfUVt5Hg=
 sigs.k8s.io/kustomize/kyaml v0.10.20/go.mod h1:TYWhGwW9vjoRh3rWqBwB/ZOXyEGRVWe7Ggc3+KZIO+c=
-sigs.k8s.io/kustomize/kyaml v0.10.22-0.20210614195535-7e8ba62e9fd9 h1:voAjfxarCKo1j3Kh34T3dSqbTi6EpfcVn/xGDvcWotE=
-sigs.k8s.io/kustomize/kyaml v0.10.22-0.20210614195535-7e8ba62e9fd9/go.mod h1:TYWhGwW9vjoRh3rWqBwB/ZOXyEGRVWe7Ggc3+KZIO+c=
+sigs.k8s.io/kustomize/kyaml v0.11.1-0.20210715170645-339e33d2f33d h1:6YDf4byqzCmB1mWvAA6SoZZE3NwpmzHKGnqPoSTaMbY=
+sigs.k8s.io/kustomize/kyaml v0.11.1-0.20210715170645-339e33d2f33d/go.mod h1:GNMwjim4Ypgp/MueD3zXHLRJEjz7RvtPae0AwlvEMFM=
 sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
 sigs.k8s.io/structured-merge-diff/v4 v4.1.0 h1:C4r9BgJ98vrKnnVCjwCSXcWjWe0NKcUQkmzDXZXGwH8=
 sigs.k8s.io/structured-merge-diff/v4 v4.1.0/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
diff --git a/internal/cmdrender/cmd.go b/internal/cmdrender/cmd.go
index b49a7589..e0bf69f9 100644
--- a/internal/cmdrender/cmd.go
+++ b/internal/cmdrender/cmd.go
@@ -25,7 +25,6 @@ import (
 	docs "github.com/GoogleContainerTools/kpt/internal/docs/generated/fndocs"
 	"github.com/GoogleContainerTools/kpt/internal/printer"
 	"github.com/GoogleContainerTools/kpt/internal/util/cmdutil"
-	"github.com/GoogleContainerTools/kpt/internal/util/pkgutil"
 	"github.com/spf13/cobra"
 )
 
@@ -39,7 +38,6 @@ func NewRunner(ctx context.Context, parent string) *Runner {
 		Example: docs.RenderExamples,
 		RunE:    r.runE,
 		PreRunE: r.preRunE,
-		PostRun: r.postRun,
 	}
 	c.Flags().StringVar(&r.resultsDirPath, "results-dir", "",
 		"path to a directory to save function results")
@@ -117,11 +115,3 @@ func (r *Runner) runE(c *cobra.Command, _ []string) error {
 
 	return cmdutil.WriteFnOutput(r.dest, outContent.String(), false, printer.FromContextOrDie(r.ctx).OutStream())
 }
-
-func (r *Runner) postRun(_ *cobra.Command, _ []string) {
-	if r.dest != "" {
-		// do not format/modify resources in package if output should be written to other dest
-		return
-	}
-	pkgutil.FormatPackage(r.pkgPath)
-}
diff --git a/internal/cmdrender/executor.go b/internal/cmdrender/executor.go
index 50e3ba60..101f45f1 100644
--- a/internal/cmdrender/executor.go
+++ b/internal/cmdrender/executor.go
@@ -31,7 +31,6 @@ import (
 	fnresult "github.com/GoogleContainerTools/kpt/pkg/api/fnresult/v1"
 	kptfilev1 "github.com/GoogleContainerTools/kpt/pkg/api/kptfile/v1"
 	"sigs.k8s.io/kustomize/kyaml/kio"
-	"sigs.k8s.io/kustomize/kyaml/kio/filters"
 	"sigs.k8s.io/kustomize/kyaml/kio/kioutil"
 	"sigs.k8s.io/kustomize/kyaml/sets"
 	"sigs.k8s.io/kustomize/kyaml/yaml"
@@ -82,15 +81,9 @@ func (e *Executor) Execute(ctx context.Context) error {
 		return err
 	}
 
-	// format resources before writing
-	_, err = filters.FormatFilter{UseSchema: true}.Filter(hctx.root.resources)
-	if err != nil {
-		return err
-	}
-
 	if e.Output == nil {
 		// the intent of the user is to modify resources in-place
-		pkgWriter := &kio.LocalPackageReadWriter{PackagePath: string(root.pkg.UniquePath)}
+		pkgWriter := &kio.LocalPackageReadWriter{PackagePath: string(root.pkg.UniquePath), PreserveSeqIndent: true}
 		err = pkgWriter.Write(hctx.root.resources)
 		if err != nil {
 			return fmt.Errorf("failed to save resources: %w", err)
diff --git a/internal/fnruntime/utils.go b/internal/fnruntime/utils.go
index 3a436152..ef373c87 100644
--- a/internal/fnruntime/utils.go
+++ b/internal/fnruntime/utils.go
@@ -32,7 +32,7 @@ func SaveResults(resultsDir string, fnResults *fnresult.ResultList) (string, err
 	out := &bytes.Buffer{}
 
 	// use kyaml encoder to ensure consistent indentation
-	e := yaml.NewEncoder(out)
+	e := yaml.NewEncoderWithOptions(out, &yaml.EncoderOptions{SeqIndent: yaml.WideSequenceStyle})
 	err := e.Encode(fnResults)
 	if err != nil {
 		return "", err
diff --git a/internal/pkg/pkg.go b/internal/pkg/pkg.go
index 8fabd190..6ecff99e 100644
--- a/internal/pkg/pkg.go
+++ b/internal/pkg/pkg.go
@@ -487,6 +487,7 @@ func (p *Pkg) LocalResources(includeMetaResources bool) (resources []*yaml.RNode
 		PackageFileName:    kptfilev1.KptFileName,
 		IncludeSubpackages: false,
 		MatchFilesGlob:     kio.MatchAll,
+		PreserveSeqIndent:  true,
 		SetAnnotations: map[string]string{
 			pkgPathAnnotation: string(p.UniquePath),
 		},
diff --git a/internal/util/addmergecomment/addmergecomment.go b/internal/util/addmergecomment/addmergecomment.go
index 03a43f1c..e650b6c3 100644
--- a/internal/util/addmergecomment/addmergecomment.go
+++ b/internal/util/addmergecomment/addmergecomment.go
@@ -33,7 +33,7 @@ type AddMergeComment struct{}
 // Process invokes AddMergeComment kyaml filter on the resources in input packages paths
 func Process(paths ...string) error {
 	for _, path := range paths {
-		inout := &kio.LocalPackageReadWriter{PackagePath: path}
+		inout := &kio.LocalPackageReadWriter{PackagePath: path, PreserveSeqIndent: true}
 		amc := &AddMergeComment{}
 		err := kio.Pipeline{
 			Inputs:  []kio.Reader{inout},
diff --git a/internal/util/cmdutil/cmdutil.go b/internal/util/cmdutil/cmdutil.go
index bcfcd6ed..3b6a500e 100644
--- a/internal/util/cmdutil/cmdutil.go
+++ b/internal/util/cmdutil/cmdutil.go
@@ -163,7 +163,7 @@ func WriteToOutput(r io.Reader, w io.Writer, outDir string) error {
 	}
 
 	return kio.Pipeline{
-		Inputs:  []kio.Reader{&kio.ByteReader{Reader: r}},
+		Inputs:  []kio.Reader{&kio.ByteReader{Reader: r, PreserveSeqIndent: true}},
 		Outputs: outputs}.Execute()
 }
 
diff --git a/internal/util/merge/merge3.go b/internal/util/merge/merge3.go
index 28b8551e..75e490b4 100644
--- a/internal/util/merge/merge3.go
+++ b/internal/util/merge/merge3.go
@@ -69,6 +69,7 @@ func (m Merge3) Merge() error {
 		SetAnnotations:     map[string]string{mergeSourceAnnotation: mergeSourceDest},
 		IncludeSubpackages: m.IncludeSubPackages,
 		PackageFileName:    kptfilev1.KptFileName,
+		PreserveSeqIndent:  true,
 	}
 	inputs = append(inputs, dest)
 
@@ -80,6 +81,7 @@ func (m Merge3) Merge() error {
 			SetAnnotations:     map[string]string{mergeSourceAnnotation: mergeSourceOriginal},
 			IncludeSubpackages: m.IncludeSubPackages,
 			PackageFileName:    kptfilev1.KptFileName,
+			PreserveSeqIndent:  true,
 		},
 		Exclusions: relPaths,
 	})
@@ -92,6 +94,7 @@ func (m Merge3) Merge() error {
 			SetAnnotations:     map[string]string{mergeSourceAnnotation: mergeSourceUpdated},
 			IncludeSubpackages: m.IncludeSubPackages,
 			PackageFileName:    kptfilev1.KptFileName,
+			PreserveSeqIndent:  true,
 		},
 		Exclusions: relPaths,
 	})
diff --git a/internal/util/pkgutil/pkgutil.go b/internal/util/pkgutil/pkgutil.go
index c46198fb..a2944be9 100644
--- a/internal/util/pkgutil/pkgutil.go
+++ b/internal/util/pkgutil/pkgutil.go
@@ -284,8 +284,9 @@ func FindSubpackagesForPaths(matcher pkg.SubpackageMatcher, recurse bool, pkgPat
 // FormatPackage formats resources and meta-resources in the package and all its subpackages
 func FormatPackage(pkgPath string) {
 	inout := &kio.LocalPackageReadWriter{
-		PackagePath:    pkgPath,
-		MatchFilesGlob: append(kio.DefaultMatch, kptfilev1.KptFileName),
+		PackagePath:       pkgPath,
+		MatchFilesGlob:    append(kio.DefaultMatch, kptfilev1.KptFileName),
+		PreserveSeqIndent: true,
 	}
 	f := &filters.FormatFilter{
 		UseSchema: true,
diff --git a/pkg/api/kptfile/v1/validation.go b/pkg/api/kptfile/v1/validation.go
index fb66469e..a2fdf657 100644
--- a/pkg/api/kptfile/v1/validation.go
+++ b/pkg/api/kptfile/v1/validation.go
@@ -155,7 +155,7 @@ func GetValidatedFnConfigFromPath(pkgPath types.UniquePath, configPath string) (
 	if err != nil {
 		return nil, fmt.Errorf("functionConfig must exist in the current package")
 	}
-	reader := kio.ByteReader{Reader: file}
+	reader := kio.ByteReader{Reader: file, PreserveSeqIndent: true}
 	nodes, err := reader.Read()
 	if err != nil {
 		return nil, fmt.Errorf("failed to read functionConfig %q: %w", configPath, err)
diff --git a/pkg/kptfile/kptfileutil/util.go b/pkg/kptfile/kptfileutil/util.go
index 3acdb0fd..830095d7 100644
--- a/pkg/kptfile/kptfileutil/util.go
+++ b/pkg/kptfile/kptfileutil/util.go
@@ -34,7 +34,7 @@ import (
 
 func WriteFile(dir string, k *kptfilev1.KptFile) error {
 	const op errors.Op = "kptfileutil.WriteFile"
-	b, err := yaml.Marshal(k)
+	b, err := yaml.MarshalWithOptions(k, &yaml.EncoderOptions{SeqIndent: yaml.WideSequenceStyle})
 	if err != nil {
 		return err
 	}
@@ -42,20 +42,8 @@ func WriteFile(dir string, k *kptfilev1.KptFile) error {
 		return errors.E(op, errors.IO, types.UniquePath(dir), err)
 	}
 
-	// convert to rNode and back to string to make indentation consistent
-	// with rest of the yaml serialization to avoid unwanted diffs
-	rNode, err := yaml.Parse(string(b))
-	if err != nil {
-		return errors.E(op, errors.YAML, types.UniquePath(dir), err)
-	}
-
-	kptFileStr, err := rNode.String()
-	if err != nil {
-		return errors.E(op, errors.YAML, types.UniquePath(dir), err)
-	}
-
 	// fyi: perm is ignored if the file already exists
-	err = ioutil.WriteFile(filepath.Join(dir, kptfilev1.KptFileName), []byte(kptFileStr), 0600)
+	err = ioutil.WriteFile(filepath.Join(dir, kptfilev1.KptFileName), b, 0600)
 	if err != nil {
 		return errors.E(op, errors.IO, types.UniquePath(dir), err)
 	}
diff --git a/thirdparty/cmdconfig/commands/cmdeval/cmdeval.go b/thirdparty/cmdconfig/commands/cmdeval/cmdeval.go
index 3da5323b..22d38730 100644
--- a/thirdparty/cmdconfig/commands/cmdeval/cmdeval.go
+++ b/thirdparty/cmdconfig/commands/cmdeval/cmdeval.go
@@ -15,7 +15,6 @@ import (
 	"github.com/GoogleContainerTools/kpt/internal/fnruntime"
 	"github.com/GoogleContainerTools/kpt/internal/printer"
 	"github.com/GoogleContainerTools/kpt/internal/util/cmdutil"
-	"github.com/GoogleContainerTools/kpt/internal/util/pkgutil"
 	kptfile "github.com/GoogleContainerTools/kpt/pkg/api/kptfile/v1"
 	"github.com/GoogleContainerTools/kpt/thirdparty/cmdconfig/commands/runner"
 	"github.com/GoogleContainerTools/kpt/thirdparty/kyaml/runfn"
@@ -36,7 +35,6 @@ func GetEvalFnRunner(ctx context.Context, parent string) *EvalFnRunner {
 		Example: docs.EvalExamples,
 		RunE:    r.runE,
 		PreRunE: r.preRunE,
-		PostRun: r.postRun,
 	}
 
 	r.Command = c
@@ -311,14 +309,3 @@ func (r *EvalFnRunner) preRunE(c *cobra.Command, args []string) error {
 
 	return nil
 }
-
-func (r *EvalFnRunner) postRun(_ *cobra.Command, args []string) {
-	if len(args) > 0 && args[0] == "-" {
-		return
-	}
-	path := "."
-	if len(args) > 0 {
-		path = args[0]
-	}
-	pkgutil.FormatPackage(path)
-}
diff --git a/thirdparty/cmdconfig/commands/cmdsource/cmdsource.go b/thirdparty/cmdconfig/commands/cmdsource/cmdsource.go
index 59ba7f12..ba24826e 100644
--- a/thirdparty/cmdconfig/commands/cmdsource/cmdsource.go
+++ b/thirdparty/cmdconfig/commands/cmdsource/cmdsource.go
@@ -73,7 +73,7 @@ func (r *SourceRunner) runE(c *cobra.Command, args []string) error {
 	// if there is a function-config specified, emit it
 	var functionConfig *yaml.RNode
 	if r.FunctionConfig != "" {
-		configs, err := kio.LocalPackageReader{PackagePath: r.FunctionConfig}.Read()
+		configs, err := kio.LocalPackageReader{PackagePath: r.FunctionConfig, PreserveSeqIndent: true}.Read()
 		if err != nil {
 			return err
 		}
@@ -98,9 +98,10 @@ func (r *SourceRunner) runE(c *cobra.Command, args []string) error {
 			return err
 		}
 		inputs = append(inputs, kio.LocalPackageReader{
-			PackagePath:    a,
-			MatchFilesGlob: matchFilesGlob,
-			FileSkipFunc:   functionConfigFilter,
+			PackagePath:       a,
+			MatchFilesGlob:    matchFilesGlob,
+			FileSkipFunc:      functionConfigFilter,
+			PreserveSeqIndent: true,
 		})
 	}
 
diff --git a/thirdparty/cmdconfig/commands/cmdtree/cmdtree.go b/thirdparty/cmdconfig/commands/cmdtree/cmdtree.go
index a962082a..9a5741f8 100644
--- a/thirdparty/cmdconfig/commands/cmdtree/cmdtree.go
+++ b/thirdparty/cmdconfig/commands/cmdtree/cmdtree.go
@@ -50,7 +50,11 @@ func (r *TreeRunner) runE(c *cobra.Command, args []string) error {
 		args = append(args, root)
 	}
 	root = filepath.Clean(args[0])
-	input = kio.LocalPackageReader{PackagePath: args[0], MatchFilesGlob: r.getMatchFilesGlob()}
+	input = kio.LocalPackageReader{
+		PackagePath:       args[0],
+		MatchFilesGlob:    r.getMatchFilesGlob(),
+		PreserveSeqIndent: true,
+	}
 	fltrs := []kio.Filter{&filters.IsLocalConfig{
 		IncludeLocalConfig: true,
 	}}
diff --git a/thirdparty/kyaml/runfn/runfn.go b/thirdparty/kyaml/runfn/runfn.go
index d0232e51..7dc2db4e 100644
--- a/thirdparty/kyaml/runfn/runfn.go
+++ b/thirdparty/kyaml/runfn/runfn.go
@@ -15,7 +15,6 @@ import (
 	"sigs.k8s.io/kustomize/kyaml/errors"
 	"sigs.k8s.io/kustomize/kyaml/fn/runtime/runtimeutil"
 	"sigs.k8s.io/kustomize/kyaml/kio"
-	"sigs.k8s.io/kustomize/kyaml/kio/filters"
 	"sigs.k8s.io/kustomize/kyaml/yaml"
 
 	"github.com/GoogleContainerTools/kpt/internal/fnruntime"
@@ -129,16 +128,17 @@ func (r RunFns) getNodesAndFilters() (
 			return nil, nil, outputPkg, err
 		}
 		outputPkg = &kio.LocalPackageReadWriter{
-			PackagePath:    string(r.uniquePath),
-			MatchFilesGlob: matchFilesGlob,
-			FileSkipFunc:   functionConfigFilter,
+			PackagePath:       string(r.uniquePath),
+			MatchFilesGlob:    matchFilesGlob,
+			FileSkipFunc:      functionConfigFilter,
+			PreserveSeqIndent: true,
 		}
 	}
 
 	if r.Input == nil {
 		p.Inputs = []kio.Reader{outputPkg}
 	} else {
-		p.Inputs = []kio.Reader{&kio.ByteReader{Reader: r.Input}}
+		p.Inputs = []kio.Reader{&kio.ByteReader{Reader: r.Input, PreserveSeqIndent: true}}
 	}
 	if err := p.Execute(); err != nil {
 		return nil, nil, outputPkg, err
@@ -189,10 +189,6 @@ func (r RunFns) runFunctions(
 		})
 	}
 
-	// add format filter at the end to consistently format output resources
-	fmtfltr := filters.FormatFilter{UseSchema: true}
-	fltrs = append(fltrs, fmtfltr)
-
 	var err error
 	pipeline := kio.Pipeline{
 		Inputs:                []kio.Reader{input},


Test patch:
diff --git a/e2e/testdata/fn-eval/consistent-formatting/.expected/diff.patch b/e2e/testdata/fn-eval/consistent-formatting/.expected/diff.patch
deleted file mode 100644
index b44f8e3d..00000000
--- a/e2e/testdata/fn-eval/consistent-formatting/.expected/diff.patch
+++ /dev/null
@@ -1,69 +0,0 @@
-diff --git a/Kptfile b/Kptfile
-index 1f982e2..d815cdb 100644
---- a/Kptfile
-+++ b/Kptfile
-@@ -2,16 +2,7 @@ apiVersion: kpt.dev/v1
- kind: Kptfile
- metadata:
-   name: nginx
--info:
--  description: describe this package
--  site: https://github.com/GoogleContainerTools/kpt
--  emails:
--    - foo@gmail.com
--  license: license text
--  keywords:
--    - tag1
--    - tag2
--  man: nginx man text
-+  namespace: staging
- upstream:
-   type: git
-   git:
-@@ -26,6 +17,16 @@ upstreamLock:
-     directory: package-examples/nginx
-     ref: package-examples/nginx/v0.2
-     commit: 4d2aa98b45ddee4b5fa45fbca16f2ff887de9efb
-+info:
-+  site: https://github.com/GoogleContainerTools/kpt
-+  emails:
-+    - foo@gmail.com
-+  license: license text
-+  description: describe this package
-+  keywords:
-+    - tag1
-+    - tag2
-+  man: nginx man text
- pipeline:
-   mutators:
-     - image: gcr.io/kpt-fn/set-namespace:v0.1.3
-diff --git a/resources.yaml b/resources.yaml
-index c0f48b0..9e31a48 100644
---- a/resources.yaml
-+++ b/resources.yaml
-@@ -14,9 +14,10 @@
- apiVersion: apps/v1
- kind: Deployment
- metadata:
-+  name: my-nginx
-+  namespace: staging
-   labels:
-     foo: bar
--  name: my-nginx
- spec:
-   replicas: 3
-   selector:
-@@ -28,8 +29,8 @@ spec:
-         app: nginx
-     spec:
-       containers:
--      - image: 'nginx:1.14.2'
--        name: nginx
--        ports:
--        - containerPort: 80
--          protocol: TCP
-+        - name: nginx
-+          image: nginx:1.14.2
-+          ports:
-+            - protocol: TCP
-+              containerPort: 80
diff --git a/e2e/testdata/fn-eval/no-op/.expected/config.yaml b/e2e/testdata/fn-eval/no-op/.expected/config.yaml
new file mode 100644
index 00000000..3d51e062
--- /dev/null
+++ b/e2e/testdata/fn-eval/no-op/.expected/config.yaml
@@ -0,0 +1,16 @@
+# Copyright 2021 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+testType: eval
+image: gcr.io/kpt-functions/no-op
diff --git a/e2e/testdata/fn-eval/consistent-formatting/.krmignore b/e2e/testdata/fn-eval/no-op/.krmignore
similarity index 100%
rename from e2e/testdata/fn-eval/consistent-formatting/.krmignore
rename to e2e/testdata/fn-eval/no-op/.krmignore
diff --git a/e2e/testdata/fn-eval/no-op/resources.yaml b/e2e/testdata/fn-eval/no-op/resources.yaml
new file mode 100644
index 00000000..217512b2
--- /dev/null
+++ b/e2e/testdata/fn-eval/no-op/resources.yaml
@@ -0,0 +1,82 @@
+# Copyright 2021 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: my-nginx
+  namespace: my-space
+  labels:
+    env: dev
+    foo: bar
+spec:
+  # comment 1
+  replicas: 3
+  selector:
+    # comment 2
+    matchLabels: # comment 3
+      # comment 4
+      app: nginx # comment 5
+  template:
+    metadata:
+      labels:
+        app: nginx
+    spec:
+      # comment 6
+      containers:
+        # comment 7
+        - name: nginx
+          image: 'nginx:1.14.2' # comment 8
+          ports:
+            # comment 9
+            - containerPort: 80 # comment 10
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: my-service
+spec:
+  ports:
+    # comment 1
+    - name: etcd-server-ssl
+      port: 2380
+    # comment 2
+    - name: etcd-client-ssl
+      port: 2379
+---
+apiVersion: constraints.gatekeeper.sh/v1beta1
+kind: EnforceFoo
+metadata:
+  name: enforce-foo
+spec:
+  parameters:
+    naming_rules:
+      - kind: Folder
+        patterns:
+          # comment 1
+          - ^(dev|prod|staging|qa|shared)$
+---
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: setters-config
+data:
+  # This should be the name of your Config Controller instance
+  cluster-name: cluster-name
+  # This should be the project where you deployed Config Controller
+  project-id: project-id
+  project-number: '1234567890123'
+  # You can leave these defaults
+  namespace: config-control
+  deployment-repo: deployment-repo
+  source-repo: source-repo
diff --git a/e2e/testdata/fn-eval/out-of-place-fnchain-stdout/.expected/config.yaml b/e2e/testdata/fn-eval/out-of-place-fnchain-stdout/.expected/config.yaml
index 15613516..f365bcf2 100644
--- a/e2e/testdata/fn-eval/out-of-place-fnchain-stdout/.expected/config.yaml
+++ b/e2e/testdata/fn-eval/out-of-place-fnchain-stdout/.expected/config.yaml
@@ -9,51 +9,53 @@ stdOut: |
   apiVersion: config.kubernetes.io/v1alpha1
   kind: ResourceList
   items:
-    # Copyright 2021 Google LLC
-    #
-    # Licensed under the Apache License, Version 2.0 (the "License");
-    # you may not use this file except in compliance with the License.
-    # You may obtain a copy of the License at
-    #
-    #      http://www.apache.org/licenses/LICENSE-2.0
-    #
-    # Unless required by applicable law or agreed to in writing, software
-    # distributed under the License is distributed on an "AS IS" BASIS,
-    # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    # See the License for the specific language governing permissions and
-    # limitations under the License.
-    - apiVersion: apps/v1
-      kind: Deployment
-      metadata:
-        name: nginx-deployment
-        namespace: staging
-        labels:
-          tier: backend
-        annotations:
-          config.kubernetes.io/index: "0"
-          config.kubernetes.io/path: resources.yaml
-          foo: bar
-      spec:
-        replicas: 3
-        selector:
-          matchLabels:
+  # Copyright 2021 Google LLC
+  #
+  # Licensed under the Apache License, Version 2.0 (the "License");
+  # you may not use this file except in compliance with the License.
+  # You may obtain a copy of the License at
+  #
+  #      http://www.apache.org/licenses/LICENSE-2.0
+  #
+  # Unless required by applicable law or agreed to in writing, software
+  # distributed under the License is distributed on an "AS IS" BASIS,
+  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  # See the License for the specific language governing permissions and
+  # limitations under the License.
+  - apiVersion: apps/v1
+    kind: Deployment
+    metadata:
+      name: nginx-deployment
+      annotations:
+        config.kubernetes.io/index: "0"
+        config.kubernetes.io/path: resources.yaml
+        internal.config.kubernetes.io/seqindent: compact
+        foo: bar
+      namespace: staging
+      labels:
+        tier: backend
+    spec:
+      replicas: 3
+      template:
+        metadata:
+          annotations:
+            foo: bar
+          labels:
             tier: backend
-        template:
-          metadata:
-            labels:
-              tier: backend
-            annotations:
-              foo: bar
-    - apiVersion: custom.io/v1
-      kind: Custom
-      metadata:
-        name: custom
-        namespace: staging
-        labels:
+      selector:
+        matchLabels:
           tier: backend
-        annotations:
-          config.kubernetes.io/index: "1"
-          config.kubernetes.io/path: resources.yaml
-          foo: bar
-      spec:
-        image: nginx:1.2.3
+  - apiVersion: custom.io/v1
+    kind: Custom
+    metadata:
+      name: custom
+      annotations:
+        config.kubernetes.io/index: "1"
+        config.kubernetes.io/path: resources.yaml
+        internal.config.kubernetes.io/seqindent: compact
+        foo: bar
+      namespace: staging
+      labels:
+        tier: backend
+    spec:
+      image: nginx:1.2.3
diff --git a/e2e/testdata/fn-eval/out-of-place-fnchain-unwrap/.expected/config.yaml b/e2e/testdata/fn-eval/out-of-place-fnchain-unwrap/.expected/config.yaml
index 86c1bbc2..3bd6c5a4 100644
--- a/e2e/testdata/fn-eval/out-of-place-fnchain-unwrap/.expected/config.yaml
+++ b/e2e/testdata/fn-eval/out-of-place-fnchain-unwrap/.expected/config.yaml
@@ -20,35 +20,48 @@ stdErr: |
   [RUNNING] "gcr.io/kpt-fn/set-labels:v0.1.3"
   [PASS] "gcr.io/kpt-fn/set-labels:v0.1.3"
 stdOut: |
+  # Copyright 2021 Google LLC
+  #
+  # Licensed under the Apache License, Version 2.0 (the "License");
+  # you may not use this file except in compliance with the License.
+  # You may obtain a copy of the License at
+  #
+  #      http://www.apache.org/licenses/LICENSE-2.0
+  #
+  # Unless required by applicable law or agreed to in writing, software
+  # distributed under the License is distributed on an "AS IS" BASIS,
+  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  # See the License for the specific language governing permissions and
+  # limitations under the License.
   apiVersion: apps/v1
   kind: Deployment
   metadata:
     name: nginx-deployment
+    annotations:
+      foo: bar
     namespace: staging
     labels:
       tier: backend
-    annotations:
-      foo: bar
   spec:
     replicas: 3
-    selector:
-      matchLabels:
-        tier: backend
     template:
       metadata:
-        labels:
-          tier: backend
         annotations:
           foo: bar
+        labels:
+          tier: backend
+    selector:
+      matchLabels:
+        tier: backend
   ---
   apiVersion: custom.io/v1
   kind: Custom
   metadata:
     name: custom
+    annotations:
+      foo: bar
     namespace: staging
     labels:
       tier: backend
-    annotations:
-      foo: bar
   spec:
     image: nginx:1.2.3
diff --git a/e2e/testdata/fn-eval/output-to-stdout/.expected/config.yaml b/e2e/testdata/fn-eval/output-to-stdout/.expected/config.yaml
index a83c39d5..cdcf75cb 100644
--- a/e2e/testdata/fn-eval/output-to-stdout/.expected/config.yaml
+++ b/e2e/testdata/fn-eval/output-to-stdout/.expected/config.yaml
@@ -16,36 +16,38 @@ stdOut: |
   apiVersion: config.kubernetes.io/v1alpha1
   kind: ResourceList
   items:
-    - # Copyright 2021 Google LLC
-      #
-      # Licensed under the Apache License, Version 2.0 (the "License");
-      # you may not use this file except in compliance with the License.
-      # You may obtain a copy of the License at
-      #
-      #      http://www.apache.org/licenses/LICENSE-2.0
-      #
-      # Unless required by applicable law or agreed to in writing, software
-      # distributed under the License is distributed on an "AS IS" BASIS,
-      # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-      # See the License for the specific language governing permissions and
-      # limitations under the License.
-      apiVersion: apps/v1
-      kind: Deployment
-      metadata:
-        name: nginx-deployment
-        namespace: staging
-        annotations:
-          config.kubernetes.io/index: "0"
-          config.kubernetes.io/path: resources.yaml
-      spec:
-        replicas: 3
-    - apiVersion: custom.io/v1
-      kind: Custom
-      metadata:
-        name: custom
-        namespace: staging
-        annotations:
-          config.kubernetes.io/index: "1"
-          config.kubernetes.io/path: resources.yaml
-      spec:
-        image: nginx:1.2.3
+  - # Copyright 2021 Google LLC
+    #
+    # Licensed under the Apache License, Version 2.0 (the "License");
+    # you may not use this file except in compliance with the License.
+    # You may obtain a copy of the License at
+    #
+    #      http://www.apache.org/licenses/LICENSE-2.0
+    #
+    # Unless required by applicable law or agreed to in writing, software
+    # distributed under the License is distributed on an "AS IS" BASIS,
+    # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    # See the License for the specific language governing permissions and
+    # limitations under the License.
+    apiVersion: apps/v1
+    kind: Deployment
+    metadata:
+      name: nginx-deployment
+      annotations:
+        config.kubernetes.io/index: "0"
+        config.kubernetes.io/path: resources.yaml
+        internal.config.kubernetes.io/seqindent: compact
+      namespace: staging
+    spec:
+      replicas: 3
+  - apiVersion: custom.io/v1
+    kind: Custom
+    metadata:
+      name: custom
+      annotations:
+        config.kubernetes.io/index: "1"
+        config.kubernetes.io/path: resources.yaml
+        internal.config.kubernetes.io/seqindent: compact
+      namespace: staging
+    spec:
+      image: nginx:1.2.3
diff --git a/e2e/testdata/fn-eval/consistent-formatting/.expected/config.yaml b/e2e/testdata/fn-eval/preserve-order-include-meta-resources/.expected/config.yaml
similarity index 100%
rename from e2e/testdata/fn-eval/consistent-formatting/.expected/config.yaml
rename to e2e/testdata/fn-eval/preserve-order-include-meta-resources/.expected/config.yaml
diff --git a/e2e/testdata/fn-eval/preserve-order-include-meta-resources/.expected/diff.patch b/e2e/testdata/fn-eval/preserve-order-include-meta-resources/.expected/diff.patch
new file mode 100644
index 00000000..d5375b4f
--- /dev/null
+++ b/e2e/testdata/fn-eval/preserve-order-include-meta-resources/.expected/diff.patch
@@ -0,0 +1,24 @@
+diff --git a/Kptfile b/Kptfile
+index 1f982e2..70d659f 100644
+--- a/Kptfile
++++ b/Kptfile
+@@ -2,6 +2,7 @@ apiVersion: kpt.dev/v1
+ kind: Kptfile
+ metadata:
+   name: nginx
++  namespace: staging
+ info:
+   description: describe this package
+   site: https://github.com/GoogleContainerTools/kpt
+diff --git a/resources.yaml b/resources.yaml
+index f79e0a8..ce92e77 100644
+--- a/resources.yaml
++++ b/resources.yaml
+@@ -17,6 +17,7 @@ metadata:
+   labels:
+     foo: bar
+   name: my-nginx
++  namespace: staging
+ spec:
+   replicas: 3
+   selector:
diff --git a/e2e/testdata/fn-eval/preserve-order-include-meta-resources/.krmignore b/e2e/testdata/fn-eval/preserve-order-include-meta-resources/.krmignore
new file mode 100644
index 00000000..9d7a4007
--- /dev/null
+++ b/e2e/testdata/fn-eval/preserve-order-include-meta-resources/.krmignore
@@ -0,0 +1,1 @@
+.expected
diff --git a/e2e/testdata/fn-eval/consistent-formatting/Kptfile b/e2e/testdata/fn-eval/preserve-order-include-meta-resources/Kptfile
similarity index 100%
rename from e2e/testdata/fn-eval/consistent-formatting/Kptfile
rename to e2e/testdata/fn-eval/preserve-order-include-meta-resources/Kptfile
diff --git a/e2e/testdata/fn-eval/consistent-formatting/resources.yaml b/e2e/testdata/fn-eval/preserve-order-include-meta-resources/resources.yaml
similarity index 86%
rename from e2e/testdata/fn-eval/consistent-formatting/resources.yaml
rename to e2e/testdata/fn-eval/preserve-order-include-meta-resources/resources.yaml
index c0f48b08..f79e0a8b 100644
--- a/e2e/testdata/fn-eval/consistent-formatting/resources.yaml
+++ b/e2e/testdata/fn-eval/preserve-order-include-meta-resources/resources.yaml
@@ -28,8 +28,8 @@ spec:
         app: nginx
     spec:
       containers:
-      - image: 'nginx:1.14.2'
-        name: nginx
-        ports:
-        - containerPort: 80
-          protocol: TCP
+        - image: nginx:1.14.2
+          name: nginx
+          ports:
+            - containerPort: 80
+              protocol: TCP
diff --git a/e2e/testdata/fn-render/fnconfig-ancestorfn-not-mutate-subpkg-config/.expected/diff.patch b/e2e/testdata/fn-render/fnconfig-ancestorfn-not-mutate-subpkg-config/.expected/diff.patch
index 79e7c68f..44e1e830 100644
--- a/e2e/testdata/fn-render/fnconfig-ancestorfn-not-mutate-subpkg-config/.expected/diff.patch
+++ b/e2e/testdata/fn-render/fnconfig-ancestorfn-not-mutate-subpkg-config/.expected/diff.patch
@@ -1,14 +1,14 @@
 diff --git a/db/resources.yaml b/db/resources.yaml
-index ac1fd96..2fa6e44 100644
+index ac1fd96..0c25e84 100644
 --- a/db/resources.yaml
 +++ b/db/resources.yaml
 @@ -15,5 +15,15 @@ apiVersion: apps/v1
  kind: StatefulSet
  metadata:
    name: db
-+  namespace: staging
 +  labels:
 +    tier: db
++  namespace: staging
  spec:
    replicas: 3
 +  selector:
@@ -36,4 +36,4 @@ index 7a494c9..254b9cd 100644
    name: custom
 +  namespace: staging
  spec:
-   image: nginx:1.2.3
+   image: nginx:1.2.3
\ No newline at end of file
diff --git a/e2e/testdata/fn-render/generator-absolute-path/.expected/diff.patch b/e2e/testdata/fn-render/generator-absolute-path/.expected/diff.patch
index 95ea29e1..7278156f 100644
--- a/e2e/testdata/fn-render/generator-absolute-path/.expected/diff.patch
+++ b/e2e/testdata/fn-render/generator-absolute-path/.expected/diff.patch
@@ -1,6 +1,6 @@
 diff --git a/another/file/out.yaml b/another/file/out.yaml
 new file mode 100644
-index 0000000..fa83ef1
+index 0000000..6d9fb79
 --- /dev/null
 +++ b/another/file/out.yaml
 @@ -0,0 +1,13 @@
@@ -13,7 +13,7 @@ index 0000000..fa83ef1
 +  template:
 +    spec:
 +      containers:
-+        - name: httpbin
-+          image: kennethreitz/httpbin
-+          ports:
-+            - containerPort: 9876
++      - name: httpbin
++        image: kennethreitz/httpbin
++        ports:
++        - containerPort: 9876
\ No newline at end of file
diff --git a/e2e/testdata/fn-render/generator/.expected/diff.patch b/e2e/testdata/fn-render/generator/.expected/diff.patch
index 2d440296..dbfcb860 100644
--- a/e2e/testdata/fn-render/generator/.expected/diff.patch
+++ b/e2e/testdata/fn-render/generator/.expected/diff.patch
@@ -1,6 +1,6 @@
 diff --git a/db/deployment_httpbin.yaml b/db/deployment_httpbin.yaml
 new file mode 100644
-index 0000000..0932111
+index 0000000..ffdf484
 --- /dev/null
 +++ b/db/deployment_httpbin.yaml
 @@ -0,0 +1,25 @@
@@ -14,21 +14,21 @@ index 0000000..0932111
 +    tier: db
 +spec:
 +  replicas: 4
-+  selector:
-+    matchLabels:
-+      app: backend
-+      tier: db
 +  template:
++    spec:
++      containers:
++      - image: kennethreitz/httpbin
++        name: httpbin
++        ports:
++        - containerPort: 9876
 +    metadata:
 +      labels:
 +        app: backend
 +        tier: db
-+    spec:
-+      containers:
-+        - name: httpbin
-+          image: kennethreitz/httpbin
-+          ports:
-+            - containerPort: 9876
++  selector:
++    matchLabels:
++      app: backend
++      tier: db
 diff --git a/db/resources.yaml b/db/resources.yaml
 index ac1fd96..49fa8df 100644
 --- a/db/resources.yaml
diff --git a/e2e/testdata/fn-render/generator/db/Kptfile b/e2e/testdata/fn-render/generator/db/Kptfile
index fef15bed..242fb15e 100644
--- a/e2e/testdata/fn-render/generator/db/Kptfile
+++ b/e2e/testdata/fn-render/generator/db/Kptfile
@@ -4,7 +4,7 @@ metadata:
   name: db
 pipeline:
   mutators:
-    - image: gcr.io/kpt-fn/starlark:v0.1.0
+    - image: gcr.io/kpt-fn/starlark:v0.2.0
       configPath: starlark-httpbin.yaml
     - image: gcr.io/kpt-fn/set-namespace:v0.1.3
       configMap:
diff --git a/e2e/testdata/fn-render/no-op/.expected/config.yaml b/e2e/testdata/fn-render/no-op/.expected/config.yaml
new file mode 100644
index 00000000..690df65f
--- /dev/null
+++ b/e2e/testdata/fn-render/no-op/.expected/config.yaml
@@ -0,0 +1,14 @@
+# Copyright 2021 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
diff --git a/e2e/testdata/fn-render/no-op/.krmignore b/e2e/testdata/fn-render/no-op/.krmignore
new file mode 100644
index 00000000..9d7a4007
--- /dev/null
+++ b/e2e/testdata/fn-render/no-op/.krmignore
@@ -0,0 +1,1 @@
+.expected
diff --git a/e2e/testdata/fn-render/no-op/Kptfile b/e2e/testdata/fn-render/no-op/Kptfile
new file mode 100644
index 00000000..d514bf27
--- /dev/null
+++ b/e2e/testdata/fn-render/no-op/Kptfile
@@ -0,0 +1,7 @@
+apiVersion: kpt.dev/v1
+kind: Kptfile
+metadata:
+  name: app
+pipeline:
+  mutators:
+    - image: gcr.io/kpt-functions/no-op
diff --git a/e2e/testdata/fn-render/no-op/resources.yaml b/e2e/testdata/fn-render/no-op/resources.yaml
new file mode 100644
index 00000000..217512b2
--- /dev/null
+++ b/e2e/testdata/fn-render/no-op/resources.yaml
@@ -0,0 +1,82 @@
+# Copyright 2021 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: my-nginx
+  namespace: my-space
+  labels:
+    env: dev
+    foo: bar
+spec:
+  # comment 1
+  replicas: 3
+  selector:
+    # comment 2
+    matchLabels: # comment 3
+      # comment 4
+      app: nginx # comment 5
+  template:
+    metadata:
+      labels:
+        app: nginx
+    spec:
+      # comment 6
+      containers:
+        # comment 7
+        - name: nginx
+          image: 'nginx:1.14.2' # comment 8
+          ports:
+            # comment 9
+            - containerPort: 80 # comment 10
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: my-service
+spec:
+  ports:
+    # comment 1
+    - name: etcd-server-ssl
+      port: 2380
+    # comment 2
+    - name: etcd-client-ssl
+      port: 2379
+---
+apiVersion: constraints.gatekeeper.sh/v1beta1
+kind: EnforceFoo
+metadata:
+  name: enforce-foo
+spec:
+  parameters:
+    naming_rules:
+      - kind: Folder
+        patterns:
+          # comment 1
+          - ^(dev|prod|staging|qa|shared)$
+---
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: setters-config
+data:
+  # This should be the name of your Config Controller instance
+  cluster-name: cluster-name
+  # This should be the project where you deployed Config Controller
+  project-id: project-id
+  project-number: '1234567890123'
+  # You can leave these defaults
+  namespace: config-control
+  deployment-repo: deployment-repo
+  source-repo: source-repo
diff --git a/e2e/testdata/fn-render/out-of-place-fnchain-stdout-results/.expected/config.yaml b/e2e/testdata/fn-render/out-of-place-fnchain-stdout-results/.expected/config.yaml
index 44a4b04e..6fcd7e43 100644
--- a/e2e/testdata/fn-render/out-of-place-fnchain-stdout-results/.expected/config.yaml
+++ b/e2e/testdata/fn-render/out-of-place-fnchain-stdout-results/.expected/config.yaml
@@ -2,54 +2,56 @@ stdOut: |
   apiVersion: config.kubernetes.io/v1alpha1
   kind: ResourceList
   items:
-    # Copyright 2021 Google LLC
-    #
-    # Licensed under the Apache License, Version 2.0 (the "License");
-    # you may not use this file except in compliance with the License.
-    # You may obtain a copy of the License at
-    #
-    #      http://www.apache.org/licenses/LICENSE-2.0
-    #
-    # Unless required by applicable law or agreed to in writing, software
-    # distributed under the License is distributed on an "AS IS" BASIS,
-    # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    # See the License for the specific language governing permissions and
-    # limitations under the License.
-    - apiVersion: apps/v1
-      kind: Deployment
-      metadata:
-        name: nginx-deployment
-        namespace: staging
-        labels:
-          tier: backend
-        annotations:
-          config.kubernetes.io/index: "0"
-          config.kubernetes.io/path: resources.yaml
-          foo: bar
-      spec:
-        replicas: 3
-        selector:
-          matchLabels:
+  # Copyright 2021 Google LLC
+  #
+  # Licensed under the Apache License, Version 2.0 (the "License");
+  # you may not use this file except in compliance with the License.
+  # You may obtain a copy of the License at
+  #
+  #      http://www.apache.org/licenses/LICENSE-2.0
+  #
+  # Unless required by applicable law or agreed to in writing, software
+  # distributed under the License is distributed on an "AS IS" BASIS,
+  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  # See the License for the specific language governing permissions and
+  # limitations under the License.
+  - apiVersion: apps/v1
+    kind: Deployment
+    metadata:
+      name: nginx-deployment
+      annotations:
+        config.kubernetes.io/index: "0"
+        config.kubernetes.io/path: resources.yaml
+        internal.config.kubernetes.io/seqindent: compact
+        foo: bar
+      namespace: staging
+      labels:
+        tier: backend
+    spec:
+      replicas: 3
+      template:
+        metadata:
+          annotations:
+            foo: bar
+          labels:
             tier: backend
-        template:
-          metadata:
-            labels:
-              tier: backend
-            annotations:
-              foo: bar
-    - apiVersion: custom.io/v1
-      kind: Custom
-      metadata:
-        name: custom
-        namespace: staging
-        labels:
+      selector:
+        matchLabels:
           tier: backend
-        annotations:
-          config.kubernetes.io/index: "1"
-          config.kubernetes.io/path: resources.yaml
-          foo: bar
-      spec:
-        image: nginx:1.2.3
+  - apiVersion: custom.io/v1
+    kind: Custom
+    metadata:
+      name: custom
+      annotations:
+        config.kubernetes.io/index: "1"
+        config.kubernetes.io/path: resources.yaml
+        internal.config.kubernetes.io/seqindent: compact
+        foo: bar
+      namespace: staging
+      labels:
+        tier: backend
+    spec:
+      image: nginx:1.2.3
 stdErr: |
   [RUNNING] "gcr.io/kpt-fn/set-namespace:v0.1.3"
   [PASS] "gcr.io/kpt-fn/set-namespace:v0.1.3"
diff --git a/e2e/testdata/fn-render/out-of-place-fnchain-stdout/.expected/config.yaml b/e2e/testdata/fn-render/out-of-place-fnchain-stdout/.expected/config.yaml
index 4dffec3a..82028df4 100644
--- a/e2e/testdata/fn-render/out-of-place-fnchain-stdout/.expected/config.yaml
+++ b/e2e/testdata/fn-render/out-of-place-fnchain-stdout/.expected/config.yaml
@@ -11,51 +11,53 @@ stdOut: |
   apiVersion: config.kubernetes.io/v1alpha1
   kind: ResourceList
   items:
-    # Copyright 2021 Google LLC
-    #
-    # Licensed under the Apache License, Version 2.0 (the "License");
-    # you may not use this file except in compliance with the License.
-    # You may obtain a copy of the License at
-    #
-    #      http://www.apache.org/licenses/LICENSE-2.0
-    #
-    # Unless required by applicable law or agreed to in writing, software
-    # distributed under the License is distributed on an "AS IS" BASIS,
-    # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    # See the License for the specific language governing permissions and
-    # limitations under the License.
-    - apiVersion: apps/v1
-      kind: Deployment
-      metadata:
-        name: nginx-deployment
-        namespace: staging
-        labels:
-          tier: backend
-        annotations:
-          config.kubernetes.io/index: "0"
-          config.kubernetes.io/path: resources.yaml
-          foo: bar
-      spec:
-        replicas: 3
-        selector:
-          matchLabels:
+  # Copyright 2021 Google LLC
+  #
+  # Licensed under the Apache License, Version 2.0 (the "License");
+  # you may not use this file except in compliance with the License.
+  # You may obtain a copy of the License at
+  #
+  #      http://www.apache.org/licenses/LICENSE-2.0
+  #
+  # Unless required by applicable law or agreed to in writing, software
+  # distributed under the License is distributed on an "AS IS" BASIS,
+  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  # See the License for the specific language governing permissions and
+  # limitations under the License.
+  - apiVersion: apps/v1
+    kind: Deployment
+    metadata:
+      name: nginx-deployment
+      annotations:
+        config.kubernetes.io/index: "0"
+        config.kubernetes.io/path: resources.yaml
+        internal.config.kubernetes.io/seqindent: compact
+        foo: bar
+      namespace: staging
+      labels:
+        tier: backend
+    spec:
+      replicas: 3
+      template:
+        metadata:
+          annotations:
+            foo: bar
+          labels:
             tier: backend
-        template:
-          metadata:
-            labels:
-              tier: backend
-            annotations:
-              foo: bar
-    - apiVersion: custom.io/v1
-      kind: Custom
-      metadata:
-        name: custom
-        namespace: staging
-        labels:
+      selector:
+        matchLabels:
           tier: backend
-        annotations:
-          config.kubernetes.io/index: "1"
-          config.kubernetes.io/path: resources.yaml
-          foo: bar
-      spec:
-        image: nginx:1.2.3
+  - apiVersion: custom.io/v1
+    kind: Custom
+    metadata:
+      name: custom
+      annotations:
+        config.kubernetes.io/index: "1"
+        config.kubernetes.io/path: resources.yaml
+        internal.config.kubernetes.io/seqindent: compact
+        foo: bar
+      namespace: staging
+      labels:
+        tier: backend
+    spec:
+      image: nginx:1.2.3
diff --git a/e2e/testdata/fn-render/out-of-place-fnchain-unwrap/.expected/config.yaml b/e2e/testdata/fn-render/out-of-place-fnchain-unwrap/.expected/config.yaml
index 64c11293..fa1bde41 100644
--- a/e2e/testdata/fn-render/out-of-place-fnchain-unwrap/.expected/config.yaml
+++ b/e2e/testdata/fn-render/out-of-place-fnchain-unwrap/.expected/config.yaml
@@ -13,35 +13,48 @@
 # limitations under the License.
 
 stdOut: |
+  # Copyright 2021 Google LLC
+  #
+  # Licensed under the Apache License, Version 2.0 (the "License");
+  # you may not use this file except in compliance with the License.
+  # You may obtain a copy of the License at
+  #
+  #      http://www.apache.org/licenses/LICENSE-2.0
+  #
+  # Unless required by applicable law or agreed to in writing, software
+  # distributed under the License is distributed on an "AS IS" BASIS,
+  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  # See the License for the specific language governing permissions and
+  # limitations under the License.
   apiVersion: apps/v1
   kind: Deployment
   metadata:
     name: nginx-deployment
+    annotations:
+      foo: bar
     namespace: staging
     labels:
       tier: backend
-    annotations:
-      foo: bar
   spec:
     replicas: 3
-    selector:
-      matchLabels:
-        tier: backend
     template:
       metadata:
-        labels:
-          tier: backend
         annotations:
           foo: bar
+        labels:
+          tier: backend
+    selector:
+      matchLabels:
+        tier: backend
   ---
   apiVersion: custom.io/v1
   kind: Custom
   metadata:
     name: custom
+    annotations:
+      foo: bar
     namespace: staging
     labels:
       tier: backend
-    annotations:
-      foo: bar
   spec:
     image: nginx:1.2.3
diff --git a/e2e/testdata/fn-render/out-of-place-stdout/.expected/config.yaml b/e2e/testdata/fn-render/out-of-place-stdout/.expected/config.yaml
index 802ba1ca..5d0abadb 100644
--- a/e2e/testdata/fn-render/out-of-place-stdout/.expected/config.yaml
+++ b/e2e/testdata/fn-render/out-of-place-stdout/.expected/config.yaml
@@ -6,36 +6,38 @@ stdOut: |
   apiVersion: config.kubernetes.io/v1alpha1
   kind: ResourceList
   items:
-    # Copyright 2021 Google LLC
-    #
-    # Licensed under the Apache License, Version 2.0 (the "License");
-    # you may not use this file except in compliance with the License.
-    # You may obtain a copy of the License at
-    #
-    #      http://www.apache.org/licenses/LICENSE-2.0
-    #
-    # Unless required by applicable law or agreed to in writing, software
-    # distributed under the License is distributed on an "AS IS" BASIS,
-    # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    # See the License for the specific language governing permissions and
-    # limitations under the License.
-    - apiVersion: apps/v1
-      kind: Deployment
-      metadata:
-        name: nginx-deployment
-        namespace: staging
-        annotations:
-          config.kubernetes.io/index: "0"
-          config.kubernetes.io/path: resources.yaml
-      spec:
-        replicas: 3
-    - apiVersion: custom.io/v1
-      kind: Custom
-      metadata:
-        name: custom
-        namespace: staging
-        annotations:
-          config.kubernetes.io/index: "1"
-          config.kubernetes.io/path: resources.yaml
-      spec:
-        image: nginx:1.2.3
+  # Copyright 2021 Google LLC
+  #
+  # Licensed under the Apache License, Version 2.0 (the "License");
+  # you may not use this file except in compliance with the License.
+  # You may obtain a copy of the License at
+  #
+  #      http://www.apache.org/licenses/LICENSE-2.0
+  #
+  # Unless required by applicable law or agreed to in writing, software
+  # distributed under the License is distributed on an "AS IS" BASIS,
+  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  # See the License for the specific language governing permissions and
+  # limitations under the License.
+  - apiVersion: apps/v1
+    kind: Deployment
+    metadata:
+      name: nginx-deployment
+      annotations:
+        config.kubernetes.io/index: "0"
+        config.kubernetes.io/path: resources.yaml
+        internal.config.kubernetes.io/seqindent: compact
+      namespace: staging
+    spec:
+      replicas: 3
+  - apiVersion: custom.io/v1
+    kind: Custom
+    metadata:
+      name: custom
+      annotations:
+        config.kubernetes.io/index: "1"
+        config.kubernetes.io/path: resources.yaml
+        internal.config.kubernetes.io/seqindent: compact
+      namespace: staging
+    spec:
+      image: nginx:1.2.3
diff --git a/e2e/testdata/fn-render/path-index-current/.expected/diff.patch b/e2e/testdata/fn-render/path-index-current/.expected/diff.patch
index 10d977a8..9e860285 100644
--- a/e2e/testdata/fn-render/path-index-current/.expected/diff.patch
+++ b/e2e/testdata/fn-render/path-index-current/.expected/diff.patch
@@ -1,6 +1,6 @@
 diff --git a/deployment_httpbin.yaml b/deployment_httpbin.yaml
 new file mode 100644
-index 0000000..fa83ef1
+index 0000000..6d9fb79
 --- /dev/null
 +++ b/deployment_httpbin.yaml
 @@ -0,0 +1,13 @@
@@ -13,7 +13,7 @@ index 0000000..fa83ef1
 +  template:
 +    spec:
 +      containers:
-+        - name: httpbin
-+          image: kennethreitz/httpbin
-+          ports:
-+            - containerPort: 9876
++      - name: httpbin
++        image: kennethreitz/httpbin
++        ports:
++        - containerPort: 9876
\ No newline at end of file
diff --git a/e2e/testdata/fn-render/path-index-descendent/.expected/diff.patch b/e2e/testdata/fn-render/path-index-descendent/.expected/diff.patch
index fcacf27f..d066f801 100644
--- a/e2e/testdata/fn-render/path-index-descendent/.expected/diff.patch
+++ b/e2e/testdata/fn-render/path-index-descendent/.expected/diff.patch
@@ -1,6 +1,6 @@
 diff --git a/db/deployment_httpbin.yaml b/db/deployment_httpbin.yaml
 new file mode 100644
-index 0000000..fa83ef1
+index 0000000..6d9fb79
 --- /dev/null
 +++ b/db/deployment_httpbin.yaml
 @@ -0,0 +1,13 @@
@@ -13,7 +13,7 @@ index 0000000..fa83ef1
 +  template:
 +    spec:
 +      containers:
-+        - name: httpbin
-+          image: kennethreitz/httpbin
-+          ports:
-+            - containerPort: 9876
++      - name: httpbin
++        image: kennethreitz/httpbin
++        ports:
++        - containerPort: 9876
diff --git a/e2e/testdata/fn-render/resource-has-pkgname-prefix/.expected/diff.patch b/e2e/testdata/fn-render/resource-has-pkgname-prefix/.expected/diff.patch
index 24d7dafb..21526818 100644
--- a/e2e/testdata/fn-render/resource-has-pkgname-prefix/.expected/diff.patch
+++ b/e2e/testdata/fn-render/resource-has-pkgname-prefix/.expected/diff.patch
@@ -1,5 +1,5 @@
 diff --git a/mysql/mysql-deployment.yaml b/mysql/mysql-deployment.yaml
-index 173c2e1..1fecfa4 100644
+index 173c2e1..11cfcb0 100644
 --- a/mysql/mysql-deployment.yaml
 +++ b/mysql/mysql-deployment.yaml
 @@ -18,8 +18,10 @@ metadata:
@@ -8,10 +8,10 @@ index 173c2e1..1fecfa4 100644
    annotations:
 -    projectId: 'PROJECT_ID' # kpt-set: ${gcloud.core.project}
 -    teamname: 'YOURTEAM' # kpt-set: ${teamname}
-+    abc: def
-+    foo: bar
 +    projectId: PROJECT_ID # kpt-set: ${gcloud.core.project}
 +    teamname: YOURTEAM # kpt-set: ${teamname}
++    foo: bar
++    abc: def
  spec:
    selector:
      app: wordpress
@@ -21,10 +21,10 @@ index 173c2e1..1fecfa4 100644
    annotations:
 -    projectId: 'PROJECT_ID' # kpt-set: ${gcloud.core.project}
 -    teamname: 'YOURTEAM' # kpt-set: ${teamname}
-+    abc: def
-+    foo: bar
 +    projectId: PROJECT_ID # kpt-set: ${gcloud.core.project}
 +    teamname: YOURTEAM # kpt-set: ${teamname}
++    foo: bar
++    abc: def
  spec:
    resources:
      requests:
@@ -34,10 +34,10 @@ index 173c2e1..1fecfa4 100644
    annotations:
 -    projectId: 'PROJECT_ID' # kpt-set: ${gcloud.core.project}
 -    teamname: 'YOURTEAM' # kpt-set: ${teamname}
-+    abc: def
-+    foo: bar
 +    projectId: PROJECT_ID # kpt-set: ${gcloud.core.project}
 +    teamname: YOURTEAM # kpt-set: ${teamname}
++    foo: bar
++    abc: def
  spec:
    selector:
      matchLabels:
@@ -46,13 +46,13 @@ index 173c2e1..1fecfa4 100644
          app: wordpress
          tier: mysql
 +      annotations:
-+        abc: def
 +        foo: bar
++        abc: def
      spec:
        containers:
          - name: mysql
 diff --git a/wordpress-deployment.yaml b/wordpress-deployment.yaml
-index f7bdc2a..3cbda32 100644
+index f7bdc2a..f555993 100644
 --- a/wordpress-deployment.yaml
 +++ b/wordpress-deployment.yaml
 @@ -16,8 +16,9 @@ metadata:
@@ -61,9 +61,9 @@ index f7bdc2a..3cbda32 100644
    annotations:
 -    projectId: 'PROJECT_ID' # kpt-set: ${gcloud.core.project}
 -    teamname: 'YOURTEAM' # kpt-set: ${teamname}
-+    abc: def
 +    projectId: PROJECT_ID # kpt-set: ${gcloud.core.project}
 +    teamname: YOURTEAM # kpt-set: ${teamname}
++    abc: def
  spec:
    type: LoadBalancer
    selector:
@@ -73,9 +73,9 @@ index f7bdc2a..3cbda32 100644
    annotations:
 -    projectId: 'PROJECT_ID' # kpt-set: ${gcloud.core.project}
 -    teamname: 'YOURTEAM' # kpt-set: ${teamname}
-+    abc: def
 +    projectId: PROJECT_ID # kpt-set: ${gcloud.core.project}
 +    teamname: YOURTEAM # kpt-set: ${teamname}
++    abc: def
  spec:
    resources:
      requests:
@@ -85,9 +85,9 @@ index f7bdc2a..3cbda32 100644
    annotations:
 -    projectId: 'PROJECT_ID' # kpt-set: ${gcloud.core.project}
 -    teamname: 'YOURTEAM' # kpt-set: ${teamname}
-+    abc: def
 +    projectId: PROJECT_ID # kpt-set: ${gcloud.core.project}
 +    teamname: YOURTEAM # kpt-set: ${teamname}
++    abc: def
  spec:
    selector:
      matchLabels:
@@ -99,4 +99,4 @@ index f7bdc2a..3cbda32 100644
 +        abc: def
      spec:
        containers:
-         - name: wordpress
+         - name: wordpress
\ No newline at end of file
diff --git a/e2e/testdata/fn-render/validate-generated-resource/.expected/diff.patch b/e2e/testdata/fn-render/validate-generated-resource/.expected/diff.patch
index 10d977a8..9bcd7cb5 100644
--- a/e2e/testdata/fn-render/validate-generated-resource/.expected/diff.patch
+++ b/e2e/testdata/fn-render/validate-generated-resource/.expected/diff.patch
@@ -1,6 +1,6 @@
 diff --git a/deployment_httpbin.yaml b/deployment_httpbin.yaml
 new file mode 100644
-index 0000000..fa83ef1
+index 0000000..6d9fb79
 --- /dev/null
 +++ b/deployment_httpbin.yaml
 @@ -0,0 +1,13 @@
@@ -13,7 +13,7 @@ index 0000000..fa83ef1
 +  template:
 +    spec:
 +      containers:
-+        - name: httpbin
-+          image: kennethreitz/httpbin
-+          ports:
-+            - containerPort: 9876
++      - name: httpbin
++        image: kennethreitz/httpbin
++        ports:
++        - containerPort: 9876
diff --git a/internal/fnruntime/runner_test.go b/internal/fnruntime/runner_test.go
index 0d71ce88..7aa8bf0c 100644
--- a/internal/fnruntime/runner_test.go
+++ b/internal/fnruntime/runner_test.go
@@ -443,24 +443,24 @@ func TestGetResourceRefMetadata(t *testing.T) {
 message: selector is required
 severity: error
 resourceRef:
-    apiVersion: apps/v1
-    kind: Deployment
-    name: nginx-deployment
+  apiVersion: apps/v1
+  kind: Deployment
+  name: nginx-deployment
 field:
-    path: selector
+  path: selector
 file:
-    path: resources.yaml
+  path: resources.yaml
 `,
 			expected: `message: selector is required
 severity: error
 resourceRef:
-    apiVersion: apps/v1
-    kind: Deployment
-    name: nginx-deployment
+  apiVersion: apps/v1
+  kind: Deployment
+  name: nginx-deployment
 field:
-    path: selector
+  path: selector
 file:
-    path: resources.yaml
+  path: resources.yaml
 `,
 		},
 		"new format with namespace": {
@@ -468,26 +468,26 @@ file:
 message: selector is required
 severity: error
 resourceRef:
-    apiVersion: apps/v1
-    kind: Deployment
-    name: nginx-deployment
-    namespace: my-namespace
+  apiVersion: apps/v1
+  kind: Deployment
+  name: nginx-deployment
+  namespace: my-namespace
 field:
-    path: selector
+  path: selector
 file:
-    path: resources.yaml
+  path: resources.yaml
 `,
 			expected: `message: selector is required
 severity: error
 resourceRef:
-    apiVersion: apps/v1
-    kind: Deployment
-    name: nginx-deployment
-    namespace: my-namespace
+  apiVersion: apps/v1
+  kind: Deployment
+  name: nginx-deployment
+  namespace: my-namespace
 field:
-    path: selector
+  path: selector
 file:
-    path: resources.yaml
+  path: resources.yaml
 `,
 		},
 		"old format with name": {
@@ -495,25 +495,25 @@ file:
 message: selector is required
 severity: error
 resourceRef:
-    apiVersion: apps/v1
-    kind: Deployment
-    metadata:
-      name: nginx-deployment
+  apiVersion: apps/v1
+  kind: Deployment
+  metadata:
+    name: nginx-deployment
 field:
-    path: selector
+  path: selector
 file:
-    path: resources.yaml
+  path: resources.yaml
 `,
 			expected: `message: selector is required
 severity: error
 resourceRef:
-    apiVersion: apps/v1
-    kind: Deployment
-    name: nginx-deployment
+  apiVersion: apps/v1
+  kind: Deployment
+  name: nginx-deployment
 field:
-    path: selector
+  path: selector
 file:
-    path: resources.yaml
+  path: resources.yaml
 `,
 		},
 		"old format with namespace": {
@@ -521,27 +521,27 @@ file:
 message: selector is required
 severity: error
 resourceRef:
-    apiVersion: apps/v1
-    kind: Deployment
-    metadata:
-      name: nginx-deployment
-      namespace: my-namespace
+  apiVersion: apps/v1
+  kind: Deployment
+  metadata:
+    name: nginx-deployment
+    namespace: my-namespace
 field:
-    path: selector
+  path: selector
 file:
-    path: resources.yaml
+  path: resources.yaml
 `,
 			expected: `message: selector is required
 severity: error
 resourceRef:
-    apiVersion: apps/v1
-    kind: Deployment
-    name: nginx-deployment
-    namespace: my-namespace
+  apiVersion: apps/v1
+  kind: Deployment
+  name: nginx-deployment
+  namespace: my-namespace
 field:
-    path: selector
+  path: selector
 file:
-    path: resources.yaml
+  path: resources.yaml
 `,
 		},
 		"no resourceRef": {
@@ -549,16 +549,16 @@ file:
 message: selector is required
 severity: error
 field:
-    path: selector
+  path: selector
 file:
-    path: resources.yaml
+  path: resources.yaml
 `,
 			expected: `message: selector is required
 severity: error
 field:
-    path: selector
+  path: selector
 file:
-    path: resources.yaml
+  path: resources.yaml
 `,
 		},
 	}
diff --git a/internal/util/cmdutil/cmdutil_test.go b/internal/util/cmdutil/cmdutil_test.go
index 7c10d1c5..2bb0057b 100644
--- a/internal/util/cmdutil/cmdutil_test.go
+++ b/internal/util/cmdutil/cmdutil_test.go
@@ -284,7 +284,8 @@ metadata:
 
 			// read the resources from output dir
 			in := &kio.LocalPackageReader{
-				PackagePath: baseDir,
+				PackagePath:       baseDir,
+				PreserveSeqIndent: true,
 			}
 			out := &bytes.Buffer{}
 
diff --git a/internal/util/get/get_test.go b/internal/util/get/get_test.go
index 664c8fe2..efa87b75 100644
--- a/internal/util/get/get_test.go
+++ b/internal/util/get/get_test.go
@@ -1319,9 +1319,10 @@ func TestCommand_Run_subpackages(t *testing.T) {
 			// Format the Kptfiles so we can diff the output without
 			// formatting issues.
 			rw := &kio.LocalPackageReadWriter{
-				NoDeleteFiles:  true,
-				PackagePath:    w.FullPackagePath(),
-				MatchFilesGlob: []string{kptfilev1.KptFileName},
+				NoDeleteFiles:     true,
+				PackagePath:       w.FullPackagePath(),
+				MatchFilesGlob:    []string{kptfilev1.KptFileName},
+				PreserveSeqIndent: true,
 			}
 			err = kio.Pipeline{
 				Inputs:  []kio.Reader{rw},
diff --git a/internal/util/update/update_test.go b/internal/util/update/update_test.go
index e76bb52d..55b9c6a7 100644
--- a/internal/util/update/update_test.go
+++ b/internal/util/update/update_test.go
@@ -1795,9 +1795,10 @@ func TestCommand_Run_local_subpackages(t *testing.T) {
 				// Format the Kptfiles so we can diff the output without
 				// formatting issues.
 				rw := &kio.LocalPackageReadWriter{
-					NoDeleteFiles:  true,
-					PackagePath:    g.LocalWorkspace.FullPackagePath(),
-					MatchFilesGlob: []string{kptfilev1.KptFileName},
+					NoDeleteFiles:     true,
+					PackagePath:       g.LocalWorkspace.FullPackagePath(),
+					MatchFilesGlob:    []string{kptfilev1.KptFileName},
+					PreserveSeqIndent: true,
 				}
 				err = kio.Pipeline{
 					Inputs:  []kio.Reader{rw},
@@ -3327,9 +3328,10 @@ func TestRun_remote_subpackages(t *testing.T) {
 			// Format the Kptfiles so we can diff the output without
 			// formatting issues.
 			rw := &kio.LocalPackageReadWriter{
-				NoDeleteFiles:  true,
-				PackagePath:    g.LocalWorkspace.FullPackagePath(),
-				MatchFilesGlob: []string{kptfilev1.KptFileName},
+				NoDeleteFiles:     true,
+				PackagePath:       g.LocalWorkspace.FullPackagePath(),
+				MatchFilesGlob:    []string{kptfilev1.KptFileName},
+				PreserveSeqIndent: true,
 			}
 			err = kio.Pipeline{
 				Inputs:  []kio.Reader{rw},
diff --git a/pkg/test/runner/config.go b/pkg/test/runner/config.go
index bed6261e..2e5e0e9f 100644
--- a/pkg/test/runner/config.go
+++ b/pkg/test/runner/config.go
@@ -22,7 +22,7 @@ import (
 
 	"github.com/GoogleContainerTools/kpt/internal/fnruntime"
 	"github.com/GoogleContainerTools/kpt/internal/types"
-	"gopkg.in/yaml.v3"
+	"sigs.k8s.io/kustomize/kyaml/yaml"
 )
 
 // EvalTestCaseConfig contains the config only for imperative
diff --git a/thirdparty/cmdconfig/commands/cmdsource/cmdsource_test.go b/thirdparty/cmdconfig/commands/cmdsource/cmdsource_test.go
index 989218d1..3046414c 100644
--- a/thirdparty/cmdconfig/commands/cmdsource/cmdsource_test.go
+++ b/thirdparty/cmdconfig/commands/cmdsource/cmdsource_test.go
@@ -83,52 +83,56 @@ spec:
 	if !assert.Equal(t, `apiVersion: config.kubernetes.io/v1alpha1
 kind: ResourceList
 items:
-  - kind: Deployment
-    metadata:
-      labels:
-        app: nginx2
-      name: foo
-      annotations:
-        app: nginx2
-        config.kubernetes.io/index: '0'
-        config.kubernetes.io/path: 'f1.yaml'
-    spec:
-      replicas: 1
-  - kind: Service
-    metadata:
-      name: foo
-      annotations:
-        app: nginx
-        config.kubernetes.io/index: '1'
-        config.kubernetes.io/path: 'f1.yaml'
-    spec:
-      selector:
-        app: nginx
-  - apiVersion: v1
-    kind: Abstraction
-    metadata:
-      name: foo
-      annotations:
-        config.kubernetes.io/function: |
-          container:
-            image: gcr.io/example/reconciler:v1
-        config.kubernetes.io/local-config: "true"
-        config.kubernetes.io/index: '0'
-        config.kubernetes.io/path: 'f2.yaml'
-    spec:
-      replicas: 3
-  - apiVersion: apps/v1
-    kind: Deployment
-    metadata:
-      labels:
-        app: nginx
-      name: bar
-      annotations:
-        app: nginx
-        config.kubernetes.io/index: '1'
-        config.kubernetes.io/path: 'f2.yaml'
-    spec:
-      replicas: 3
+- kind: Deployment
+  metadata:
+    labels:
+      app: nginx2
+    name: foo
+    annotations:
+      app: nginx2
+      config.kubernetes.io/index: '0'
+      config.kubernetes.io/path: 'f1.yaml'
+      internal.config.kubernetes.io/seqindent: 'compact'
+  spec:
+    replicas: 1
+- kind: Service
+  metadata:
+    name: foo
+    annotations:
+      app: nginx
+      config.kubernetes.io/index: '1'
+      config.kubernetes.io/path: 'f1.yaml'
+      internal.config.kubernetes.io/seqindent: 'compact'
+  spec:
+    selector:
+      app: nginx
+- apiVersion: v1
+  kind: Abstraction
+  metadata:
+    name: foo
+    annotations:
+      config.kubernetes.io/function: |
+        container:
+          image: gcr.io/example/reconciler:v1
+      config.kubernetes.io/local-config: "true"
+      config.kubernetes.io/index: '0'
+      config.kubernetes.io/path: 'f2.yaml'
+      internal.config.kubernetes.io/seqindent: 'compact'
+  spec:
+    replicas: 3
+- apiVersion: apps/v1
+  kind: Deployment
+  metadata:
+    labels:
+      app: nginx
+    name: bar
+    annotations:
+      app: nginx
+      config.kubernetes.io/index: '1'
+      config.kubernetes.io/path: 'f2.yaml'
+      internal.config.kubernetes.io/seqindent: 'compact'
+  spec:
+    replicas: 3
 `, b.String()) {
 		return
 	}
@@ -345,52 +349,56 @@ spec:
 	if !assert.Equal(t, `apiVersion: config.kubernetes.io/v1alpha1
 kind: ResourceList
 items:
-  - kind: Deployment
-    metadata:
-      labels:
-        app: nginx2
-      name: foo
-      annotations:
-        app: nginx2
-        config.kubernetes.io/index: '0'
-        config.kubernetes.io/path: 'f1.yaml'
-    spec:
-      replicas: 1
-  - kind: Service
-    metadata:
-      name: foo
-      annotations:
-        app: nginx
-        config.kubernetes.io/index: '1'
-        config.kubernetes.io/path: 'f1.yaml'
-    spec:
-      selector:
-        app: nginx
-  - apiVersion: v1
-    kind: Abstraction
-    metadata:
-      name: foo
-      annotations:
-        config.kubernetes.io/function: |
-          container:
-            image: gcr.io/example/reconciler:v1
-        config.kubernetes.io/local-config: "true"
-        config.kubernetes.io/index: '0'
-        config.kubernetes.io/path: 'f2.yaml'
-    spec:
-      replicas: 3
-  - apiVersion: apps/v1
-    kind: Deployment
-    metadata:
-      labels:
-        app: nginx
-      name: bar
-      annotations:
-        app: nginx
-        config.kubernetes.io/index: '1'
-        config.kubernetes.io/path: 'f2.yaml'
-    spec:
-      replicas: 3
+- kind: Deployment
+  metadata:
+    labels:
+      app: nginx2
+    name: foo
+    annotations:
+      app: nginx2
+      config.kubernetes.io/index: '0'
+      config.kubernetes.io/path: 'f1.yaml'
+      internal.config.kubernetes.io/seqindent: 'compact'
+  spec:
+    replicas: 1
+- kind: Service
+  metadata:
+    name: foo
+    annotations:
+      app: nginx
+      config.kubernetes.io/index: '1'
+      config.kubernetes.io/path: 'f1.yaml'
+      internal.config.kubernetes.io/seqindent: 'compact'
+  spec:
+    selector:
+      app: nginx
+- apiVersion: v1
+  kind: Abstraction
+  metadata:
+    name: foo
+    annotations:
+      config.kubernetes.io/function: |
+        container:
+          image: gcr.io/example/reconciler:v1
+      config.kubernetes.io/local-config: "true"
+      config.kubernetes.io/index: '0'
+      config.kubernetes.io/path: 'f2.yaml'
+      internal.config.kubernetes.io/seqindent: 'compact'
+  spec:
+    replicas: 3
+- apiVersion: apps/v1
+  kind: Deployment
+  metadata:
+    labels:
+      app: nginx
+    name: bar
+    annotations:
+      app: nginx
+      config.kubernetes.io/index: '1'
+      config.kubernetes.io/path: 'f2.yaml'
+      internal.config.kubernetes.io/seqindent: 'compact'
+  spec:
+    replicas: 3
 `, b.String()) {
 		return
 	}
@@ -456,8 +464,8 @@ func TestSourceCommandJSON(t *testing.T) {
 	expected := `apiVersion: config.kubernetes.io/v1alpha1
 kind: ResourceList
 items:
-  - {"kind": "Deployment", "metadata": {"labels": {"app": "nginx2"}, "name": "foo", "annotations": {"app": "nginx2", config.kubernetes.io/index: '0', config.kubernetes.io/path: 'f1.json'}}, "spec": {"replicas": 1}}
-  - {"apiVersion": "v1", "kind": "Abstraction", "metadata": {"name": "foo", "annotations": {"config.kubernetes.io/function": "container:\n  image: gcr.io/example/reconciler:v1\n", "config.kubernetes.io/local-config": "true", config.kubernetes.io/index: '0', config.kubernetes.io/path: 'f2.json'}}, "spec": {"replicas": 3}}
+- {"kind": "Deployment", "metadata": {"labels": {"app": "nginx2"}, "name": "foo", "annotations": {"app": "nginx2", config.kubernetes.io/index: '0', config.kubernetes.io/path: 'f1.json', internal.config.kubernetes.io/seqindent: 'compact'}}, "spec": {"replicas": 1}}
+- {"apiVersion": "v1", "kind": "Abstraction", "metadata": {"name": "foo", "annotations": {"config.kubernetes.io/function": "container:\n  image: gcr.io/example/reconciler:v1\n", "config.kubernetes.io/local-config": "true", config.kubernetes.io/index: '0', config.kubernetes.io/path: 'f2.json', internal.config.kubernetes.io/seqindent: 'compact'}}, "spec": {"replicas": 3}}
 `
 
 	if !assert.Equal(t, expected, b.String()) {
diff --git a/thirdparty/kyaml/runfn/runfn_test.go b/thirdparty/kyaml/runfn/runfn_test.go
index bd2a8b9d..3e48f042 100644
--- a/thirdparty/kyaml/runfn/runfn_test.go
+++ b/thirdparty/kyaml/runfn/runfn_test.go
@@ -372,7 +372,7 @@ func TestCmd_Execute_setInput(t *testing.T) {
 		},
 	}
 
-	read, err := kio.LocalPackageReader{PackagePath: dir}.Read()
+	read, err := kio.LocalPackageReader{PackagePath: dir, PreserveSeqIndent: true}.Read()
 	if !assert.NoError(t, err) {
 		t.FailNow()
 	}