Merge pull request #1890 from joncwong/merge3

Integrate merge3 as command for 3-way merges
This commit is contained in:
Kubernetes Prow Robot
2020-01-02 07:43:41 -08:00
committed by GitHub
5 changed files with 334 additions and 0 deletions

View File

@@ -74,6 +74,7 @@ func NewConfigCommand(name string) *cobra.Command {
root.AddCommand(commands.CatCommand(name))
root.AddCommand(commands.FmtCommand(name))
root.AddCommand(commands.MergeCommand(name))
root.AddCommand(commands.Merge3Command(name))
root.AddCommand(commands.CountCommand(name))
root.AddCommand(commands.RunFnCommand(name))
root.AddCommand(commands.SubCommand(name))

View File

@@ -0,0 +1,23 @@
## merge3
[Alpha] Merge diff of Resource configuration files into a destination (3-way)
### Synopsis
[Alpha] Merge diff of Resource configuration files into a destination (3-way)
Merge3 performs a 3-way merge by applying the diff between 2 sets of Resources to a 3rd set.
Merge3 may be for rebasing changes to a forked set of configuration -- e.g. compute the difference between the original
set of Resources that was forked and an updated set of those Resources, then apply that difference to the fork.
If a field value differs between the ORIGINAL_DIR and UPDATED_DIR, the value from the UPDATED_DIR is taken and applied
to the Resource in the DEST_DIR.
For information on merge rules, run:
kustomize config docs-merge3
### Examples
kustomize config merge3 --ancestor a/ --from b/ --to c/

View File

@@ -0,0 +1,55 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package commands
import (
"github.com/spf13/cobra"
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
"sigs.k8s.io/kustomize/kyaml/kio/filters"
)
func GetMerge3Runner(name string) *Merge3Runner {
r := &Merge3Runner{}
c := &cobra.Command{
Use: "merge3 --ancestor [ORIGINAL_DIR] --from [UPDATED_DIR] --to [DESTINATION_DIR]",
Short: commands.Merge3Short,
Long: commands.Merge3Long,
Example: commands.Merge3Examples,
RunE: r.runE,
}
fixDocs(name, c)
c.Flags().StringVar(&r.ancestor, "ancestor", "",
"Path to original package")
c.Flags().StringVar(&r.fromDir, "from", "",
"Path to updated package")
c.Flags().StringVar(&r.toDir, "to", "",
"Path to destination package")
r.Command = c
return r
}
func Merge3Command(name string) *cobra.Command {
return GetMerge3Runner(name).Command
}
// Merge3Runner contains the run function
type Merge3Runner struct {
Command *cobra.Command
ancestor string
fromDir string
toDir string
}
func (r *Merge3Runner) runE(c *cobra.Command, args []string) error {
err := filters.Merge3{
OriginalPath: r.ancestor,
UpdatedPath: r.fromDir,
DestPath: r.toDir,
}.Merge()
if err != nil {
return err
}
return nil
}

View File

@@ -0,0 +1,236 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package commands_test
import (
"io/ioutil"
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
"sigs.k8s.io/kustomize/cmd/config/internal/commands"
"sigs.k8s.io/kustomize/kyaml/copyutil"
)
// TestMerge3Command verifies the merge3 correctly applies the diff between 2 sets of resources into another
func TestMerge3Command(t *testing.T) {
datadir, err := ioutil.TempDir("", "test-data")
defer os.RemoveAll(datadir)
if !assert.NoError(t, err) {
return
}
err = ioutil.WriteFile(filepath.Join(datadir, "java-deployment.resource.yaml"), []byte(`apiVersion: apps/v1
kind: Deployment
metadata:
name: app
labels:
app: java
spec:
replicas: 1
selector:
matchLabels:
app: java
template:
metadata:
labels:
app: java
spec:
restartPolicy: Always
containers:
- name: app
image: gcr.io/project/app:version
command:
- java
- -jar
- /app.jar
ports:
- containerPort: 8080
envFrom:
- configMapRef:
name: app-config
env:
- name: JAVA_OPTS
value: -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap
-Djava.security.egd=file:/dev/./urandom
imagePullPolicy: Always
minReadySeconds: 5
`), 0600)
if !assert.NoError(t, err) {
return
}
expected_dir, err := ioutil.TempDir("", "test-data-expected")
defer os.RemoveAll(expected_dir)
if !assert.NoError(t, err) {
return
}
err = ioutil.WriteFile(filepath.Join(expected_dir, "java-deployment.resource.yaml"), []byte(`apiVersion: apps/v1
kind: Deployment
metadata:
name: app
labels:
app: java
new-local: label
new-remote: label
spec:
replicas: 3
selector:
matchLabels:
app: java
template:
metadata:
labels:
app: java
spec:
restartPolicy: Always
containers:
- name: app
image: gcr.io/project/app:version
command:
- java
- -jar
- /app.jar
- otherstuff
args:
- foo
ports:
- containerPort: 8080
envFrom:
- configMapRef:
name: app-config
env:
- name: JAVA_OPTS
value: -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap
-Djava.security.egd=file:/dev/./urandom
imagePullPolicy: Always
minReadySeconds: 20
`), 0600)
if !assert.NoError(t, err) {
return
}
updated_dir, err := ioutil.TempDir("", "test-data-updated")
defer os.RemoveAll(updated_dir)
if !assert.NoError(t, err) {
return
}
err = ioutil.WriteFile(filepath.Join(updated_dir, "java-deployment.resource.yaml"), []byte(`apiVersion: apps/v1
kind: Deployment
metadata:
name: app
labels:
app: java
new-remote: label
spec:
replicas: 3
selector:
matchLabels:
app: java
template:
metadata:
labels:
app: java
spec:
restartPolicy: Always
containers:
- name: app
image: gcr.io/project/app:version
command:
- java
- -jar
- /app.jar
- otherstuff
ports:
- containerPort: 8080
envFrom:
- configMapRef:
name: app-config
env:
- name: JAVA_OPTS
value: -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap
-Djava.security.egd=file:/dev/./urandom
imagePullPolicy: Always
minReadySeconds: 5
`), 0600)
if !assert.NoError(t, err) {
return
}
dest_dir, err := ioutil.TempDir("", "test-data-dest")
defer os.RemoveAll(dest_dir)
if !assert.NoError(t, err) {
return
}
err = ioutil.WriteFile(filepath.Join(dest_dir, "java-deployment.resource.yaml"), []byte(`apiVersion: apps/v1
kind: Deployment
metadata:
name: app
labels:
app: java
new-local: label
spec:
replicas: 2
selector:
matchLabels:
app: java
template:
metadata:
labels:
app: java
spec:
restartPolicy: Always
containers:
- name: app
image: gcr.io/project/app:version
command:
- java
- -jar
- /app.jar
args:
- foo
ports:
- containerPort: 8080
envFrom:
- configMapRef:
name: app-config
env:
- name: JAVA_OPTS
value: -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap
-Djava.security.egd=file:/dev/./urandom
imagePullPolicy: Always
minReadySeconds: 20
`), 0600)
if !assert.NoError(t, err) {
return
}
// Perform merge3 with newly created sets
r := commands.GetMerge3Runner("")
r.Command.SetArgs([]string{
"--ancestor",
datadir,
"--from",
updated_dir,
"--to",
dest_dir,
})
if !assert.NoError(t, r.Command.Execute()) {
return
}
diffs, err := copyutil.Diff(dest_dir, expected_dir)
if !assert.NoError(t, err) {
t.FailNow()
}
// Verify there are no diffs
if !assert.Empty(t, diffs.List()) {
t.FailNow()
}
}

View File

@@ -136,6 +136,25 @@ For information on merge rules, run:
var MergeExamples = `
cat resources_and_patches.yaml | kustomize config merge > merged_resources.yaml`
var Merge3Short = `[Alpha] Merge diff of Resource configuration files into a destination (3-way)`
var Merge3Long = `
[Alpha] Merge diff of Resource configuration files into a destination (3-way)
Merge3 performs a 3-way merge by applying the diff between 2 sets of Resources to a 3rd set.
Merge3 may be for rebasing changes to a forked set of configuration -- e.g. compute the difference between the original
set of Resources that was forked and an updated set of those Resources, then apply that difference to the fork.
If a field value differs between the ORIGINAL_DIR and UPDATED_DIR, the value from the UPDATED_DIR is taken and applied
to the Resource in the DEST_DIR.
For information on merge rules, run:
kustomize config docs-merge3
`
var Merge3Examples = `
kustomize config merge3 --ancestor a/ --from b/ --to c/`
var RunFnsShort = `[Alpha] Reoncile config functions to Resources.`
var RunFnsLong = `
[Alpha] Reconcile config functions to Resources.