diff --git a/pkg/devfile/adapters/common/utils.go b/pkg/devfile/adapters/common/utils.go index 4f869897af5..55a2cf951ac 100644 --- a/pkg/devfile/adapters/common/utils.go +++ b/pkg/devfile/adapters/common/utils.go @@ -8,7 +8,9 @@ import ( "k8s.io/klog" devfilev1 "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2" + devfileParser "github.com/devfile/library/pkg/devfile/parser" parsercommon "github.com/devfile/library/pkg/devfile/parser/data/v2/common" + devfilefs "github.com/devfile/library/pkg/testingutil/filesystem" ) // PredefinedDevfileCommands encapsulates constants for predefined devfile commands @@ -219,3 +221,37 @@ func GetSyncFilesFromAttributes(commandsMap PushCommandsMap) map[string]string { } return syncMap } + +// RemoveDevfileURIContents removes contents +// which are used via a URI in the devfile +func RemoveDevfileURIContents(devfile devfileParser.DevfileObj, componentContext string) error { + return removeDevfileURIContents(devfile, componentContext, devfilefs.DefaultFs{}) +} + +func removeDevfileURIContents(devfile devfileParser.DevfileObj, componentContext string, fs devfilefs.Filesystem) error { + components, err := devfile.Data.GetComponents(parsercommon.DevfileOptions{}) + if err != nil { + return err + } + for _, component := range components { + var uri string + if component.Kubernetes != nil && component.Kubernetes.Uri != "" { + uri = component.Kubernetes.Uri + } + + if component.Openshift != nil && component.Openshift.Uri != "" { + uri = component.Openshift.Uri + } + + if uri == "" { + continue + } + + completePath := filepath.Join(componentContext, uri) + err = fs.Remove(completePath) + if err != nil { + return err + } + } + return nil +} diff --git a/pkg/devfile/adapters/common/utils_test.go b/pkg/devfile/adapters/common/utils_test.go index 8e6768ed6bf..5509cde3477 100644 --- a/pkg/devfile/adapters/common/utils_test.go +++ b/pkg/devfile/adapters/common/utils_test.go @@ -2,6 +2,7 @@ package common import ( "os" + "path/filepath" "reflect" "testing" @@ -11,6 +12,8 @@ import ( devfileParser "github.com/devfile/library/pkg/devfile/parser" parsercommon "github.com/devfile/library/pkg/devfile/parser/data/v2/common" "github.com/devfile/library/pkg/testingutil" + devfileFileSystem "github.com/devfile/library/pkg/testingutil/filesystem" + odotestingutil "github.com/openshift/odo/pkg/testingutil" ) func TestIsEnvPresent(t *testing.T) { @@ -576,3 +579,98 @@ func TestGetCommandsFromEvent(t *testing.T) { } } + +func Test_removeDevfileURIContents(t *testing.T) { + fs := devfileFileSystem.NewFakeFs() + + uriFolderName := "kubernetes" + + fileName0 := "odo-service-some-service.yaml" + fileName1 := "odo-url-some-url.yaml" + + err := fs.MkdirAll(uriFolderName, os.ModePerm) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + + file0, err := fs.Create(filepath.Join(uriFolderName, fileName0)) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + + file1, err := fs.Create(filepath.Join(uriFolderName, fileName1)) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + + addURIComponents := func(obj devfileParser.DevfileObj, name, uri string) error { + err = obj.Data.AddComponents([]devfilev1.Component{{ + Name: name, + ComponentUnion: devfilev1.ComponentUnion{ + Kubernetes: &devfilev1.KubernetesComponent{ + K8sLikeComponent: devfilev1.K8sLikeComponent{ + BaseComponent: devfilev1.BaseComponent{}, + K8sLikeComponentLocation: devfilev1.K8sLikeComponentLocation{ + Uri: uri, + }, + }, + }, + }, + }}) + if err != nil { + return err + } + return nil + } + + devfileObj := odotestingutil.GetTestDevfileObj(fs) + err = addURIComponents(devfileObj, "some-service.yaml", file0.Name()) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + err = addURIComponents(devfileObj, "some-url.yaml", file1.Name()) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + + devfileObjWithMissingFiles := odotestingutil.GetTestDevfileObj(fs) + err = addURIComponents(devfileObjWithMissingFiles, "some-blah.yaml", file0.Name()+"blah") + if err != nil { + t.Errorf("unexpected error: %v", err) + } + + type args struct { + devfile devfileParser.DevfileObj + componentContext string + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "case 1: the files mentioned in the URI exists", + args: args{ + devfile: devfileObj, + componentContext: "", + }, + }, + { + name: "case 2: the files mentioned in the URI don't exists", + args: args{ + devfile: devfileObjWithMissingFiles, + componentContext: "", + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := removeDevfileURIContents(tt.args.devfile, tt.args.componentContext, fs); (err != nil) != tt.wantErr { + t.Errorf("RemoveDevfileURIContents() error = %v, wantErr %v", err, tt.wantErr) + } + + _ = fs.RemoveAll(uriFolderName) + }) + } +} diff --git a/pkg/odo/cli/component/delete.go b/pkg/odo/cli/component/delete.go index 868391d25ec..8b609c0e1db 100644 --- a/pkg/odo/cli/component/delete.go +++ b/pkg/odo/cli/component/delete.go @@ -14,6 +14,8 @@ import ( "github.com/openshift/odo/pkg/component" "github.com/openshift/odo/pkg/config" + "github.com/openshift/odo/pkg/devfile" + "github.com/openshift/odo/pkg/devfile/adapters/common" "github.com/openshift/odo/pkg/log" appCmd "github.com/openshift/odo/pkg/odo/cli/application" projectCmd "github.com/openshift/odo/pkg/odo/cli/project" @@ -21,6 +23,7 @@ import ( "github.com/openshift/odo/pkg/odo/genericclioptions" odoutil "github.com/openshift/odo/pkg/odo/util" "github.com/openshift/odo/pkg/odo/util/completion" + "github.com/openshift/odo/pkg/service" ktemplates "k8s.io/kubectl/pkg/util/templates" ) @@ -83,9 +86,13 @@ func NewDeleteOptions() *DeleteOptions { // Complete completes log args func (do *DeleteOptions) Complete(name string, cmd *cobra.Command, args []string) (err error) { - if do.componentContext == "" { - do.componentContext = LocalDirectoryDefaultLocation + dir, err := os.Getwd() + if err != nil { + return err + } + + do.componentContext = dir } do.devfilePath = filepath.Join(do.componentContext, DevfilePath) @@ -248,6 +255,28 @@ func (do *DeleteOptions) DevFileRun() (err error) { } if do.componentForceDeleteFlag { + devfileObj, err := devfile.ParseFromFile(do.devfilePath) + if err != nil { + return err + } + + err = common.RemoveDevfileURIContents(devfileObj, do.ComponentContext) + if err != nil { + return err + } + + empty, err := util.IsEmpty(service.UriFolder) + if err != nil { + return err + } + + if empty { + err = os.RemoveAll(service.UriFolder) + if err != nil { + return err + } + } + if !util.CheckPathExists(do.devfilePath) { return fmt.Errorf("devfile.yaml does not exist in the current directory") } diff --git a/pkg/service/service.go b/pkg/service/service.go index 193a374de7f..b649643bcd1 100644 --- a/pkg/service/service.go +++ b/pkg/service/service.go @@ -41,7 +41,9 @@ const ServiceLabel = "app.kubernetes.io/service-name" // ServiceKind is the kind of the service in the service binding object const ServiceKind = "app.kubernetes.io/service-kind" -const uriFolder = "kubernetes" +const UriFolder = "kubernetes" + +const filePrefix = "odo-service-" // GetCSV checks if the CR provided by the user in the YAML file exists in the namesapce // It returns a CR (string representation) and CSV (Operator) upon successfully @@ -535,9 +537,9 @@ func AddKubernetesComponent(crd, name, componentContext string, devfile parser.D // AddKubernetesComponent adds the crd information to a separate file and adds the uri information to a devfile component func addKubernetesComponent(crd, name, componentContext string, devfileObj parser.DevfileObj, fs devfilefs.Filesystem) error { - filePath := filepath.Join(componentContext, uriFolder, name+".yaml") - if _, err := fs.Stat(filepath.Join(componentContext, uriFolder)); os.IsNotExist(err) { - err = fs.MkdirAll(filepath.Join(componentContext, uriFolder), os.ModePerm) + filePath := filepath.Join(componentContext, UriFolder, filePrefix+name+".yaml") + if _, err := fs.Stat(filepath.Join(componentContext, UriFolder)); os.IsNotExist(err) { + err = fs.MkdirAll(filepath.Join(componentContext, UriFolder), os.ModePerm) if err != nil { return err } @@ -559,7 +561,7 @@ func addKubernetesComponent(crd, name, componentContext string, devfileObj parse K8sLikeComponent: devfile.K8sLikeComponent{ BaseComponent: devfile.BaseComponent{}, K8sLikeComponentLocation: devfile.K8sLikeComponentLocation{ - Uri: filepath.Join(uriFolder, name+".yaml"), + Uri: filepath.Join(UriFolder, filePrefix+name+".yaml"), }, }, }, diff --git a/pkg/service/service_test.go b/pkg/service/service_test.go index 22de4cd450e..d241114a885 100644 --- a/pkg/service/service_test.go +++ b/pkg/service/service_test.go @@ -186,7 +186,7 @@ func TestDeleteKubernetesComponentFromDevfile(t *testing.T) { K8sLikeComponent: devfile.K8sLikeComponent{ BaseComponent: devfile.BaseComponent{}, K8sLikeComponentLocation: devfile.K8sLikeComponentLocation{ - Uri: filepath.Join(uriFolder, filepath.Base(testFileName.Name())), + Uri: filepath.Join(UriFolder, filepath.Base(testFileName.Name())), }, }, }, @@ -288,7 +288,7 @@ spec: }, []uriComponent{ { name: "service1", - uri: filepath.Join(uriFolder, filepath.Base(testFileName.Name())), + uri: filepath.Join(UriFolder, filepath.Base(testFileName.Name())), }, }), }, @@ -409,7 +409,7 @@ spec: }, []uriComponent{ { name: "service1", - uri: filepath.Join(uriFolder, filepath.Base(testFileName.Name())), + uri: filepath.Join(UriFolder, filepath.Base(testFileName.Name())), }, }), Ctx: devfileCtx.FakeContext(fs, parser.OutputDevfileYamlPath), @@ -503,7 +503,7 @@ spec: }, []uriComponent{ { name: "service1", - uri: filepath.Join(uriFolder, filepath.Base(testFileName.Name())), + uri: filepath.Join(UriFolder, filepath.Base(testFileName.Name())), }, }), Ctx: devfileCtx.FakeContext(fs, parser.OutputDevfileYamlPath), @@ -563,11 +563,11 @@ func setup(testFolderName string, fs devfileFileSystem.Filesystem) (devfileFileS if err != nil { return nil, err } - err = fs.MkdirAll(filepath.Join(testFolderName, uriFolder), os.ModePerm) + err = fs.MkdirAll(filepath.Join(testFolderName, UriFolder), os.ModePerm) if err != nil { return nil, err } - testFileName, err := fs.Create(filepath.Join(testFolderName, uriFolder, "example.yaml")) + testFileName, err := fs.Create(filepath.Join(testFolderName, UriFolder, "example.yaml")) if err != nil { return nil, err } @@ -624,15 +624,15 @@ func Test_addKubernetesComponent(t *testing.T) { tt.args.fs = fs if tt.args.uriFolderExists || tt.args.fileAlreadyExists { - err := fs.MkdirAll(uriFolder, os.ModePerm) + err := fs.MkdirAll(UriFolder, os.ModePerm) if err != nil { t.Errorf("unexpected error: %v", err) } - defer os.RemoveAll(uriFolder) + defer os.RemoveAll(UriFolder) } if tt.args.fileAlreadyExists { - testFileName, err := fs.Create(filepath.Join(uriFolder, tt.args.name+".yaml")) + testFileName, err := fs.Create(filepath.Join(UriFolder, filePrefix+tt.args.name+".yaml")) if err != nil { t.Errorf("unexpected error: %v", err) }