diff --git a/pkg/commands/commands.go b/pkg/commands/commands.go index 7a887fc47..20648465a 100644 --- a/pkg/commands/commands.go +++ b/pkg/commands/commands.go @@ -123,6 +123,7 @@ func newCmdSet(fsys fs.FileSystem) *cobra.Command { c.AddCommand( newCmdSetNamePrefix(fsys), + newCmdSetNamespace(fsys), newCmdSetImageTag(fsys), ) return c diff --git a/pkg/commands/setnamespace.go b/pkg/commands/setnamespace.go new file mode 100644 index 000000000..f215d91e5 --- /dev/null +++ b/pkg/commands/setnamespace.go @@ -0,0 +1,83 @@ +/* +Copyright 2018 The Kubernetes Authors. + +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. +*/ + +package commands + +import ( + "errors" + "fmt" + "strings" + + "github.com/kubernetes-sigs/kustomize/pkg/constants" + "github.com/kubernetes-sigs/kustomize/pkg/fs" + "github.com/spf13/cobra" + "k8s.io/apimachinery/pkg/util/validation" +) + +type setNamespaceOptions struct { + namespace string +} + +// newCmdSetNamespace sets the value of the namespace field in the kustomization. +func newCmdSetNamespace(fsys fs.FileSystem) *cobra.Command { + var o setNamespaceOptions + + cmd := &cobra.Command{ + Use: "namespace", + Short: "Sets the value of the namespace field in the kustomization file", + Example: ` +The command + set namespace staging +will add the field "namespace: staging" to the kustomization file if it doesn't exist, +and overwrite the value with "staging" if the field does exist. +`, + RunE: func(cmd *cobra.Command, args []string) error { + err := o.Validate(args) + if err != nil { + return err + } + return o.RunSetNamespace(fsys) + }, + } + return cmd +} + +// Validate validates setNamespace command. +func (o *setNamespaceOptions) Validate(args []string) error { + if len(args) != 1 { + return errors.New("must specify exactly one namespace value") + } + ns := args[0] + if errs := validation.IsDNS1123Label(ns); len(errs) != 0 { + return fmt.Errorf("%q is not a valid namespace name: %s", ns, strings.Join(errs, ";")) + } + o.namespace = ns + return nil +} + +// RunSetNamespace runs setNamespace command (does real work). +func (o *setNamespaceOptions) RunSetNamespace(fsys fs.FileSystem) error { + mf, err := newKustomizationFile(constants.KustomizationFileName, fsys) + if err != nil { + return err + } + m, err := mf.read() + if err != nil { + return err + } + m.Namespace = o.namespace + return mf.write(m) +} diff --git a/pkg/commands/setnamespace_test.go b/pkg/commands/setnamespace_test.go new file mode 100644 index 000000000..d4d1a3682 --- /dev/null +++ b/pkg/commands/setnamespace_test.go @@ -0,0 +1,103 @@ +/* +Copyright 2018 The Kubernetes Authors. + +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. +*/ + +package commands + +import ( + "fmt" + "strings" + "testing" + + "github.com/kubernetes-sigs/kustomize/pkg/constants" + "github.com/kubernetes-sigs/kustomize/pkg/fs" +) + +const ( + goodNamespaceValue = "staging" +) + +func TestSetNamespaceHappyPath(t *testing.T) { + fakeFS := fs.MakeFakeFS() + fakeFS.WriteFile(constants.KustomizationFileName, []byte(kustomizationContent)) + + cmd := newCmdSetNamespace(fakeFS) + args := []string{goodNamespaceValue} + err := cmd.RunE(cmd, args) + if err != nil { + t.Errorf("unexpected cmd error: %v", err) + } + content, err := fakeFS.ReadFile(constants.KustomizationFileName) + if err != nil { + t.Errorf("unexpected read error: %v", err) + } + expected := []byte(fmt.Sprintf("namespace: %s", goodNamespaceValue)) + if !strings.Contains(string(content), string(expected)) { + t.Errorf("expected namespace in kustomization file") + } +} + +func TestSetNamespaceOverride(t *testing.T) { + fakeFS := fs.MakeFakeFS() + fakeFS.WriteFile(constants.KustomizationFileName, []byte(kustomizationContent)) + + cmd := newCmdSetNamespace(fakeFS) + args := []string{goodNamespaceValue} + err := cmd.RunE(cmd, args) + if err != nil { + t.Errorf("unexpected cmd error: %v", err) + } + args = []string{"newnamespace"} + err = cmd.RunE(cmd, args) + if err != nil { + t.Errorf("unexpected cmd error: %v", err) + } + content, err := fakeFS.ReadFile(constants.KustomizationFileName) + if err != nil { + t.Errorf("unexpected read error: %v", err) + } + expected := []byte("namespace: newnamespace") + if !strings.Contains(string(content), string(expected)) { + t.Errorf("expected namespace in kustomization file %s", string(content)) + } +} + +func TestSetNamespaceNoArgs(t *testing.T) { + fakeFS := fs.MakeFakeFS() + + cmd := newCmdSetNamespace(fakeFS) + err := cmd.Execute() + if err == nil { + t.Errorf("expected error: %v", err) + } + if err.Error() != "must specify exactly one namespace value" { + t.Errorf("incorrect error: %v", err.Error()) + } +} + +func TestSetNamespaceInvalid(t *testing.T) { + fakeFS := fs.MakeFakeFS() + fakeFS.WriteFile(constants.KustomizationFileName, []byte(kustomizationContent)) + + cmd := newCmdSetNamespace(fakeFS) + args := []string{"/badnamespace/"} + err := cmd.RunE(cmd, args) + if err == nil { + t.Errorf("expected error: %v", err) + } + if !strings.Contains(err.Error(), "is not a valid namespace name") { + t.Errorf("unexpected error: %v", err.Error()) + } +}