mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-10 08:20:59 +00:00
Add localize command handle (#4959)
* Add localize command handle * Align to kustomize command conventions * Print success msg
This commit is contained in:
@@ -17,6 +17,7 @@ import (
|
||||
"sigs.k8s.io/kustomize/kustomize/v4/commands/build"
|
||||
"sigs.k8s.io/kustomize/kustomize/v4/commands/create"
|
||||
"sigs.k8s.io/kustomize/kustomize/v4/commands/edit"
|
||||
"sigs.k8s.io/kustomize/kustomize/v4/commands/localize"
|
||||
"sigs.k8s.io/kustomize/kustomize/v4/commands/openapi"
|
||||
"sigs.k8s.io/kustomize/kustomize/v4/commands/version"
|
||||
"sigs.k8s.io/kustomize/kyaml/filesys"
|
||||
@@ -53,6 +54,7 @@ See https://sigs.k8s.io/kustomize
|
||||
create.NewCmdCreate(fSys, pvd.GetResourceFactory()),
|
||||
version.NewCmdVersion(stdOut),
|
||||
openapi.NewCmdOpenAPI(stdOut),
|
||||
localize.NewCmdLocalize(fSys, stdOut),
|
||||
)
|
||||
configcobra.AddCommands(c, konfig.ProgramName)
|
||||
|
||||
|
||||
98
kustomize/commands/localize/localize.go
Normal file
98
kustomize/commands/localize/localize.go
Normal file
@@ -0,0 +1,98 @@
|
||||
// Copyright 2022 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package localize
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
lclzr "sigs.k8s.io/kustomize/api/krusty/localizer"
|
||||
"sigs.k8s.io/kustomize/kyaml/errors"
|
||||
"sigs.k8s.io/kustomize/kyaml/filesys"
|
||||
)
|
||||
|
||||
const numArgs = 2
|
||||
|
||||
type arguments struct {
|
||||
target string
|
||||
dest string
|
||||
}
|
||||
|
||||
type flags struct {
|
||||
scope string
|
||||
}
|
||||
|
||||
// NewCmdLocalize returns a new localize command.
|
||||
func NewCmdLocalize(fs filesys.FileSystem, writer io.Writer) *cobra.Command {
|
||||
log.SetOutput(writer)
|
||||
var f flags
|
||||
cmd := &cobra.Command{
|
||||
Use: "localize [target [destination]]",
|
||||
Short: "[Alpha] Creates localized copy of target kustomization root at destination",
|
||||
Long: `[Alpha] Creates copy of target kustomization directory or
|
||||
versioned URL at destination, where remote references in the original
|
||||
are replaced by local references to the downloaded remote content.
|
||||
|
||||
If target is not specified, the current working directory will be used.
|
||||
Destination is a path to a new directory in an existing directory. If
|
||||
destination is not specified, a new directory will be created in the current
|
||||
working directory.
|
||||
|
||||
For details, see: https://kubectl.docs.kubernetes.io/references/kustomize/cmd/
|
||||
|
||||
Disclaimer:
|
||||
This command does not yet localize helm or KRM plugin fields. This command also
|
||||
alphabetizes kustomization fields in the localized copy.
|
||||
`,
|
||||
Example: `
|
||||
# Localize the current working directory, with default scope and destination
|
||||
kustomize localize
|
||||
|
||||
# Localize some local directory, with scope and default destination
|
||||
kustomize localize /home/path/scope/target --scope /home/path/scope
|
||||
|
||||
# Localize remote at set destination relative to working directory
|
||||
kustomize localize https://github.com/kubernetes-sigs/kustomize//api/krusty/testdata/localize/simple?ref=v4.5.7 path/non-existing-dir
|
||||
`,
|
||||
SilenceUsage: true,
|
||||
Args: cobra.MaximumNArgs(numArgs),
|
||||
RunE: func(cmd *cobra.Command, rawArgs []string) error {
|
||||
args := matchArgs(rawArgs)
|
||||
dst, err := lclzr.Run(fs, args.target, f.scope, args.dest)
|
||||
if err != nil {
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
successMsg := fmt.Sprintf("SUCCESS: localized %q to directory %s\n", args.target, dst)
|
||||
_, err = writer.Write([]byte(successMsg))
|
||||
return errors.Wrap(err)
|
||||
},
|
||||
}
|
||||
// no shorthand to avoid conflation with other flags
|
||||
cmd.Flags().StringVar(&f.scope,
|
||||
"scope",
|
||||
"",
|
||||
`Path to directory inside of which localize is limited to running.
|
||||
Cannot specify for remote targets, as scope is by default the containing repo.
|
||||
If not specified for local target, scope defaults to target.
|
||||
`)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// matchArgs matches user-entered userArgs, which cannot exceed max length, with
|
||||
// arguments.
|
||||
func matchArgs(rawArgs []string) arguments {
|
||||
var args arguments
|
||||
switch len(rawArgs) {
|
||||
case numArgs:
|
||||
args.dest = rawArgs[1]
|
||||
fallthrough
|
||||
case 1:
|
||||
args.target = rawArgs[0]
|
||||
case 0:
|
||||
args.target = filesys.SelfDir
|
||||
}
|
||||
return args
|
||||
}
|
||||
153
kustomize/commands/localize/localize_test.go
Normal file
153
kustomize/commands/localize/localize_test.go
Normal file
@@ -0,0 +1,153 @@
|
||||
// Copyright 2022 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package localize_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"log"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
loctest "sigs.k8s.io/kustomize/api/testutils/localizertest"
|
||||
"sigs.k8s.io/kustomize/kustomize/v4/commands/localize"
|
||||
)
|
||||
|
||||
const deployment = `apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: nginx-deployment
|
||||
labels:
|
||||
app: nginx
|
||||
spec:
|
||||
replicas: 3
|
||||
selector:
|
||||
matchLabels:
|
||||
app: nginx
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx:1.14.2
|
||||
ports:
|
||||
- containerPort: 80
|
||||
`
|
||||
|
||||
func TestScopeFlag(t *testing.T) {
|
||||
kustomizations := map[string]string{
|
||||
filepath.Join("target", "kustomization.yaml"): fmt.Sprintf(`resources:
|
||||
- %s
|
||||
`, filepath.Join("..", "base")),
|
||||
filepath.Join("base", "kustomization.yaml"): `resources:
|
||||
- deployment.yaml
|
||||
`,
|
||||
filepath.Join("base", "deployment.yaml"): deployment,
|
||||
}
|
||||
expected, actual, testDir := loctest.PrepareFs(t, []string{
|
||||
"target",
|
||||
"base",
|
||||
}, kustomizations)
|
||||
|
||||
cmd := localize.NewCmdLocalize(actual, new(bytes.Buffer))
|
||||
require.NoError(t, cmd.Flags().Set("scope", testDir.String()))
|
||||
err := cmd.RunE(cmd, []string{
|
||||
testDir.Join("target"),
|
||||
testDir.Join("dst"),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
loctest.SetupDir(t, expected, testDir.Join("dst"), kustomizations)
|
||||
loctest.CheckFs(t, testDir.String(), expected, actual)
|
||||
}
|
||||
|
||||
func TestOptionalArgs(t *testing.T) {
|
||||
for name, args := range map[string][]string{
|
||||
"no_target": {},
|
||||
"no_dst": {"."},
|
||||
} {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
kust := map[string]string{
|
||||
"kustomization.yaml": `resources:
|
||||
- deployment.yaml
|
||||
`,
|
||||
"deployment.yaml": deployment,
|
||||
}
|
||||
expected, actual, testDir := loctest.PrepareFs(t, []string{
|
||||
"target",
|
||||
}, nil)
|
||||
target := testDir.Join("target")
|
||||
loctest.SetupDir(t, actual, target, kust)
|
||||
loctest.SetWorkingDir(t, target)
|
||||
|
||||
buffy := new(bytes.Buffer)
|
||||
cmd := localize.NewCmdLocalize(actual, buffy)
|
||||
err := cmd.RunE(cmd, args)
|
||||
require.NoError(t, err)
|
||||
|
||||
loctest.SetupDir(t, expected, target, kust)
|
||||
dst := filepath.Join(target, "localized-target")
|
||||
loctest.SetupDir(t, expected, dst, kust)
|
||||
loctest.CheckFs(t, testDir.String(), expected, actual)
|
||||
|
||||
successMsg := fmt.Sprintf(`SUCCESS: localized "." to directory %s
|
||||
`, dst)
|
||||
require.Equal(t, successMsg, buffy.String())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestOutput(t *testing.T) {
|
||||
kustomization := map[string]string{
|
||||
"kustomization.yaml": `namePrefix: test-
|
||||
`,
|
||||
}
|
||||
expected, actual, target := loctest.PrepareFs(t, nil, kustomization)
|
||||
|
||||
buffy := new(bytes.Buffer)
|
||||
cmd := localize.NewCmdLocalize(actual, buffy)
|
||||
err := cmd.RunE(cmd, []string{
|
||||
target.String(),
|
||||
target.Join("dst"),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
loctest.SetupDir(t, expected, target.Join("dst"), kustomization)
|
||||
loctest.CheckFs(t, target.String(), expected, actual)
|
||||
|
||||
successMsg := fmt.Sprintf(`SUCCESS: localized "%s" to directory %s
|
||||
`, target.String(), target.Join("dst"))
|
||||
require.Equal(t, successMsg, buffy.String())
|
||||
|
||||
const msg = "Check that cmd log output is hooked to buffy."
|
||||
log.Print(msg)
|
||||
require.Contains(t, buffy.String(), msg)
|
||||
}
|
||||
|
||||
func TestAlpha(t *testing.T) {
|
||||
_, actual, _ := loctest.PrepareFs(t, nil, map[string]string{
|
||||
"kustomization.yaml": `namePrefix: test-`,
|
||||
})
|
||||
|
||||
cmd := localize.NewCmdLocalize(actual, new(bytes.Buffer))
|
||||
require.Contains(t, cmd.Short, "[Alpha]")
|
||||
require.Contains(t, cmd.Long, "[Alpha]")
|
||||
}
|
||||
|
||||
func TestTooManyArgs(t *testing.T) {
|
||||
_, actual, target := loctest.PrepareFs(t, nil, map[string]string{
|
||||
"kustomization.yaml": `namePrefix: test-`,
|
||||
})
|
||||
|
||||
cmd := localize.NewCmdLocalize(actual, new(bytes.Buffer))
|
||||
err := cmd.Args(cmd, []string{
|
||||
target.String(),
|
||||
target.Join("dst"),
|
||||
target.String(),
|
||||
})
|
||||
require.EqualError(t, err, "accepts at most 2 arg(s), received 3")
|
||||
}
|
||||
Reference in New Issue
Block a user