Skip to content

Commit c6bc428

Browse files
authored
Heal Comments on Package Resources Update (#3084)
1 parent a97673b commit c6bc428

File tree

9 files changed

+179
-14
lines changed

9 files changed

+179
-14
lines changed

porch/pkg/engine/builtin_test.go

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ package engine
1616

1717
import (
1818
"context"
19-
"flag"
2019
"os"
2120
"path/filepath"
2221
"testing"
@@ -25,15 +24,10 @@ import (
2524
"github.com/google/go-cmp/cmp"
2625
)
2726

28-
var (
29-
update = flag.Bool("update", false, "update golden files")
27+
const (
28+
updateGoldenFiles = "UPDATE_GOLDEN_FILES"
3029
)
3130

32-
func TestMain(m *testing.M) {
33-
flag.Parse()
34-
os.Exit(m.Run())
35-
}
36-
3731
func TestUnknownBuiltinFunctionMutation(t *testing.T) {
3832
const doesNotExist = "function-does-not-exist"
3933
m, err := newBuiltinFunctionMutation(doesNotExist)
@@ -62,7 +56,7 @@ func TestPackageContext(t *testing.T) {
6256

6357
expectedPackage := filepath.Join(testdata, "expected")
6458

65-
if *update {
59+
if os.Getenv(updateGoldenFiles) != "" {
6660
if err := os.RemoveAll(expectedPackage); err != nil {
6761
t.Fatalf("Failed to update golden files: %v", err)
6862
}

porch/pkg/engine/engine.go

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ import (
3434
"github.com/GoogleContainerTools/kpt/porch/pkg/repository"
3535
"go.opentelemetry.io/otel"
3636
"go.opentelemetry.io/otel/trace"
37+
"sigs.k8s.io/kustomize/kyaml/comments"
38+
"sigs.k8s.io/kustomize/kyaml/kio"
39+
"sigs.k8s.io/kustomize/kyaml/yaml"
3740
)
3841

3942
var tracer = otel.Tracer("engine")
@@ -508,7 +511,10 @@ func (m *mutationReplaceResources) Apply(ctx context.Context, resources reposito
508511
patch := &api.PackagePatchTaskSpec{}
509512

510513
old := resources.Contents
511-
new := m.newResources.Spec.Resources
514+
new, err := healConfig(old, m.newResources.Spec.Resources)
515+
if err != nil {
516+
return repository.PackageResources{}, nil, fmt.Errorf("failed to heal resources: %w", err)
517+
}
512518

513519
for k, newV := range new {
514520
oldV, ok := old[k]
@@ -546,3 +552,48 @@ func (m *mutationReplaceResources) Apply(ctx context.Context, resources reposito
546552

547553
return repository.PackageResources{Contents: new}, task, nil
548554
}
555+
556+
func healConfig(old, new map[string]string) (map[string]string, error) {
557+
// Copy comments from old config to new
558+
oldResources, err := (&packageReader{
559+
input: repository.PackageResources{Contents: old},
560+
extra: map[string]string{},
561+
}).Read()
562+
if err != nil {
563+
return nil, fmt.Errorf("failed to read old packge resources: %w", err)
564+
}
565+
566+
var filter kio.FilterFunc = func(r []*yaml.RNode) ([]*yaml.RNode, error) {
567+
for _, n := range r {
568+
for _, original := range oldResources {
569+
if n.GetNamespace() == original.GetNamespace() &&
570+
n.GetName() == original.GetName() &&
571+
n.GetApiVersion() == original.GetApiVersion() &&
572+
n.GetKind() == original.GetKind() {
573+
comments.CopyComments(original, n)
574+
}
575+
}
576+
}
577+
return r, nil
578+
}
579+
580+
out := &packageWriter{
581+
output: repository.PackageResources{
582+
Contents: map[string]string{},
583+
},
584+
}
585+
586+
if err := (kio.Pipeline{
587+
Inputs: []kio.Reader{&packageReader{
588+
input: repository.PackageResources{Contents: new},
589+
extra: map[string]string{},
590+
}},
591+
Filters: []kio.Filter{filter},
592+
Outputs: []kio.Writer{out},
593+
ContinueOnEmptyResult: true,
594+
}).Execute(); err != nil {
595+
return nil, err
596+
}
597+
598+
return out.output.Contents, nil
599+
}

porch/pkg/engine/kio.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ func (w *packageWriter) Write(nodes []*yaml.RNode) error {
8484
Writer: buf,
8585
ClearAnnotations: []string{
8686
kioutil.PathAnnotation,
87+
kioutil.LegacyPathAnnotation,
8788
},
8889
}
8990
if err := bw.Write(nodes); err != nil {

porch/pkg/engine/replace_test.go

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
// Copyright 2022 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package engine
16+
17+
import (
18+
"bytes"
19+
"context"
20+
"path/filepath"
21+
"testing"
22+
23+
"github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1"
24+
"github.com/GoogleContainerTools/kpt/porch/pkg/repository"
25+
"github.com/google/go-cmp/cmp"
26+
"sigs.k8s.io/kustomize/kyaml/yaml"
27+
)
28+
29+
func TestReplaceResources(t *testing.T) {
30+
ctx := context.Background()
31+
32+
input := readPackage(t, filepath.Join("testdata", "replace"))
33+
nocomment := removeComments(t, input)
34+
35+
replace := &mutationReplaceResources{
36+
newResources: &v1alpha1.PackageRevisionResources{
37+
Spec: v1alpha1.PackageRevisionResourcesSpec{
38+
Resources: nocomment.Contents,
39+
},
40+
},
41+
oldResources: &v1alpha1.PackageRevisionResources{
42+
Spec: v1alpha1.PackageRevisionResourcesSpec{
43+
Resources: input.Contents,
44+
},
45+
},
46+
}
47+
48+
output, _, err := replace.Apply(ctx, input)
49+
if err != nil {
50+
t.Fatalf("mutationReplaceResources.Apply failed: %v", err)
51+
}
52+
53+
if !cmp.Equal(input, output) {
54+
t.Errorf("Diff: (-want,+got): %s", cmp.Diff(input, output))
55+
}
56+
}
57+
58+
func removeComments(t *testing.T, r repository.PackageResources) repository.PackageResources {
59+
t.Helper()
60+
61+
out := repository.PackageResources{
62+
Contents: map[string]string{},
63+
}
64+
65+
for k, v := range r.Contents {
66+
var data interface{}
67+
if err := yaml.Unmarshal([]byte(v), &data); err != nil {
68+
t.Fatalf("Failed to unmarshal %q: %v", k, err)
69+
}
70+
71+
var nocomment bytes.Buffer
72+
encoder := yaml.NewEncoder(&nocomment)
73+
encoder.SetIndent(0)
74+
if err := encoder.Encode(data); err != nil {
75+
t.Fatalf("Failed to re-encode yaml output: %v", err)
76+
}
77+
78+
out.Contents[k] = nocomment.String()
79+
}
80+
81+
return out
82+
}

porch/pkg/engine/testdata/context/expected/Kptfile

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,5 @@ apiVersion: kpt.dev/v1
22
kind: Kptfile
33
metadata:
44
name: input
5-
annotations:
6-
config.kubernetes.io/path: 'Kptfile'
75
info:
86
description: Builtin Function Test Package

porch/pkg/engine/testdata/context/expected/bucket.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ metadata:
55
namespace: bucket-namespace
66
annotations:
77
cnrm.cloud.google.com/project-id: bucket-project
8-
config.kubernetes.io/path: 'bucket.yaml'
98
spec:
109
storageClass: standard
1110
uniformBucketLevelAccess: true

porch/pkg/engine/testdata/context/expected/package-context.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,5 @@ metadata:
44
name: kptfile.kpt.dev
55
annotations:
66
config.kubernetes.io/local-config: "true"
7-
config.kubernetes.io/path: 'package-context.yaml'
87
data:
98
name: input
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# top comment
2+
apiVersion: kpt.dev/v1
3+
# Kptfile info
4+
info:
5+
# Kptfile description
6+
description: A Google Cloud Storage bucket
7+
# Kptfile kind
8+
kind: Kptfile
9+
# Kptfile metadata
10+
metadata:
11+
annotations:
12+
blueprints.cloud.google.com/title: Google Cloud Storage Bucket blueprint
13+
name: simple-bucket
14+
# Kptfile pipeline
15+
pipeline:
16+
# Kptfile mutators
17+
mutators:
18+
- configMap:
19+
name: updated-bucket-name
20+
namespace: updated-namespace
21+
project-id: updated-project-id
22+
storage-class: updated-storage-class
23+
image: gcr.io/kpt-fn/apply-setters:v0.2.0
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# top comment
2+
apiVersion: storage.cnrm.cloud.google.com/v1beta1
3+
kind: StorageBucket
4+
# metadata comment
5+
metadata: # kpt-merge: config-control/blueprints-project-bucket
6+
# annotations comment
7+
annotations:
8+
cnrm.cloud.google.com/force-destroy: "false"
9+
cnrm.cloud.google.com/project-id: blueprints-project # kpt-set: ${project-id}
10+
name: blueprints-project-bucket # kpt-set: ${project-id}-${name}
11+
namespace: config-control # kpt-set: ${namespace}
12+
# spec comment
13+
spec:
14+
storageClass: standard # kpt-set: ${storage-class}
15+
uniformBucketLevelAccess: true
16+
# Versioning is enabled
17+
versioning:
18+
enabled: false

0 commit comments

Comments
 (0)