mirror of
https://github.com/redhat-developer/odo.git
synced 2025-10-19 03:06:19 +03:00
Separate layers - Application + Project (#5293)
* Application interface * Application describe * Application list * Fix --output/-o flag * Test Run() * Tests on application pkg * Unit tests on kclient relative to application * comment * Add ComponentList method to Application * Project interface * Project CLI tests * Dharmit review
This commit is contained in:
@@ -1,97 +1,12 @@
|
||||
package application
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/redhat-developer/odo/pkg/kclient"
|
||||
"k8s.io/klog"
|
||||
import "github.com/redhat-developer/odo/pkg/component"
|
||||
|
||||
applabels "github.com/redhat-developer/odo/pkg/application/labels"
|
||||
"github.com/redhat-developer/odo/pkg/component"
|
||||
"github.com/redhat-developer/odo/pkg/util"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
const (
|
||||
appAPIVersion = "odo.dev/v1alpha1"
|
||||
appKind = "Application"
|
||||
appList = "List"
|
||||
)
|
||||
|
||||
// List all applications names in current project by looking at `app` labels in deployments
|
||||
func List(client kclient.ClientInterface) ([]string, error) {
|
||||
if client == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Get all Deployments with the "app" label
|
||||
deploymentAppNames, err := client.GetDeploymentLabelValues(applabels.ApplicationLabel, applabels.ApplicationLabel)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unable to list applications from deployments")
|
||||
}
|
||||
|
||||
// Filter out any names, as there could be multiple components but within the same application
|
||||
return util.RemoveDuplicates(deploymentAppNames), nil
|
||||
}
|
||||
|
||||
// Exists checks whether the given app exist or not in the list of applications
|
||||
func Exists(app string, client kclient.ClientInterface) (bool, error) {
|
||||
|
||||
appList, err := List(client)
|
||||
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
for _, appName := range appList {
|
||||
if appName == app {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// Delete the given application by deleting deployments and services instances belonging to this application
|
||||
func Delete(client kclient.ClientInterface, name string) error {
|
||||
klog.V(4).Infof("Deleting application %s", name)
|
||||
|
||||
labels := applabels.GetLabels(name, false)
|
||||
|
||||
// delete application from cluster
|
||||
err := client.Delete(labels, false)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "unable to delete application %s", name)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetMachineReadableFormat returns resource information in machine readable format
|
||||
func GetMachineReadableFormat(client kclient.ClientInterface, appName string, projectName string) App {
|
||||
componentList, _ := component.GetComponentNames(client, appName)
|
||||
appDef := App{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: appKind,
|
||||
APIVersion: appAPIVersion,
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: appName,
|
||||
Namespace: projectName,
|
||||
},
|
||||
Spec: AppSpec{
|
||||
Components: componentList,
|
||||
},
|
||||
}
|
||||
return appDef
|
||||
}
|
||||
|
||||
// GetMachineReadableFormatForList returns application list in machine readable format
|
||||
func GetMachineReadableFormatForList(apps []App) AppList {
|
||||
return AppList{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: appList,
|
||||
APIVersion: appAPIVersion,
|
||||
},
|
||||
ListMeta: metav1.ListMeta{},
|
||||
Items: apps,
|
||||
}
|
||||
type Client interface {
|
||||
List() ([]string, error)
|
||||
Exists(app string) (bool, error)
|
||||
Delete(name string) error
|
||||
ComponentList(name string) ([]component.Component, error)
|
||||
GetMachineReadableFormat(appName string, projectName string) App
|
||||
GetMachineReadableFormatForList(apps []App) AppList
|
||||
}
|
||||
|
||||
@@ -1,192 +0,0 @@
|
||||
package application
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
applabels "github.com/redhat-developer/odo/pkg/application/labels"
|
||||
componentlabels "github.com/redhat-developer/odo/pkg/component/labels"
|
||||
"github.com/redhat-developer/odo/pkg/kclient"
|
||||
"github.com/redhat-developer/odo/pkg/testingutil"
|
||||
"github.com/redhat-developer/odo/pkg/version"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
ktesting "k8s.io/client-go/testing"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func TestGetMachineReadableFormat(t *testing.T) {
|
||||
type args struct {
|
||||
appName string
|
||||
projectName string
|
||||
active bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want App
|
||||
}{
|
||||
{
|
||||
|
||||
name: "Test Case: machine readable output for application",
|
||||
args: args{
|
||||
appName: "myapp",
|
||||
projectName: "myproject",
|
||||
active: true,
|
||||
},
|
||||
want: App{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: appKind,
|
||||
APIVersion: appAPIVersion,
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "myapp",
|
||||
Namespace: "myproject",
|
||||
},
|
||||
Spec: AppSpec{
|
||||
Components: []string{"frontend"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
deploymentList := appsv1.DeploymentList{
|
||||
Items: []appsv1.Deployment{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "frontend-myapp",
|
||||
Namespace: "myproject",
|
||||
Labels: map[string]string{
|
||||
applabels.ApplicationLabel: "myapp",
|
||||
componentlabels.ComponentLabel: "frontend",
|
||||
componentlabels.ComponentTypeLabel: "nodejs",
|
||||
applabels.ManagedBy: "odo",
|
||||
applabels.ManagerVersion: version.VERSION,
|
||||
},
|
||||
},
|
||||
Spec: appsv1.DeploymentSpec{
|
||||
Template: corev1.PodTemplateSpec{
|
||||
Spec: corev1.PodSpec{
|
||||
Containers: []corev1.Container{
|
||||
{
|
||||
Name: "dummyContainer",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "backend-app",
|
||||
Namespace: "myproject",
|
||||
Labels: map[string]string{
|
||||
applabels.ApplicationLabel: "app",
|
||||
componentlabels.ComponentLabel: "backend",
|
||||
componentlabels.ComponentTypeLabel: "java",
|
||||
applabels.ManagedBy: "odo",
|
||||
applabels.ManagerVersion: version.VERSION,
|
||||
},
|
||||
},
|
||||
Spec: appsv1.DeploymentSpec{
|
||||
Template: corev1.PodTemplateSpec{
|
||||
Spec: corev1.PodSpec{
|
||||
Containers: []corev1.Container{
|
||||
{
|
||||
Name: "dummyContainer",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Fake the client with the appropriate arguments
|
||||
client, fakeClientSet := kclient.FakeNew()
|
||||
|
||||
// fake the project
|
||||
fakeClientSet.Kubernetes.PrependReactor("get", "projects", func(action ktesting.Action) (handled bool, ret runtime.Object, err error) {
|
||||
return true, &testingutil.FakeOnlyOneExistingProjects().Items[0], nil
|
||||
})
|
||||
|
||||
//fake the deployments
|
||||
fakeClientSet.Kubernetes.PrependReactor("list", "deployments", func(action ktesting.Action) (bool, runtime.Object, error) {
|
||||
return true, &deploymentList, nil
|
||||
})
|
||||
|
||||
for i := range deploymentList.Items {
|
||||
fakeClientSet.Kubernetes.PrependReactor("get", "deployments", func(action ktesting.Action) (bool, runtime.Object, error) {
|
||||
return true, &deploymentList.Items[i], nil
|
||||
})
|
||||
}
|
||||
if got := GetMachineReadableFormat(client, tt.args.appName, tt.args.projectName); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("GetMachineReadableFormat() = %v,\n want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetMachineReadableFormatForList(t *testing.T) {
|
||||
type args struct {
|
||||
apps []App
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want AppList
|
||||
}{
|
||||
{
|
||||
name: "Test Case: Machine Readable for Application List",
|
||||
args: args{
|
||||
apps: []App{
|
||||
{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: appKind,
|
||||
APIVersion: appAPIVersion,
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "myapp",
|
||||
},
|
||||
Spec: AppSpec{
|
||||
Components: []string{"frontend"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: AppList{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: appList,
|
||||
APIVersion: appAPIVersion,
|
||||
},
|
||||
ListMeta: metav1.ListMeta{},
|
||||
Items: []App{
|
||||
{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: appKind,
|
||||
APIVersion: appAPIVersion,
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "myapp",
|
||||
},
|
||||
Spec: AppSpec{
|
||||
Components: []string{"frontend"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := GetMachineReadableFormatForList(tt.args.apps); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("GetMachineReadableFormatForList() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
112
pkg/application/kubernetes.go
Normal file
112
pkg/application/kubernetes.go
Normal file
@@ -0,0 +1,112 @@
|
||||
package application
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
|
||||
applabels "github.com/redhat-developer/odo/pkg/application/labels"
|
||||
"github.com/redhat-developer/odo/pkg/component"
|
||||
"github.com/redhat-developer/odo/pkg/kclient"
|
||||
"github.com/redhat-developer/odo/pkg/machineoutput"
|
||||
"github.com/redhat-developer/odo/pkg/util"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/klog"
|
||||
)
|
||||
|
||||
type kubernetesClient struct {
|
||||
client kclient.ClientInterface
|
||||
}
|
||||
|
||||
func NewClient(client kclient.ClientInterface) Client {
|
||||
return kubernetesClient{
|
||||
client: client,
|
||||
}
|
||||
}
|
||||
|
||||
// List all applications names in current project by looking at `app` labels in deployments
|
||||
func (o kubernetesClient) List() ([]string, error) {
|
||||
if o.client == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Get all Deployments with the "app" label
|
||||
deploymentAppNames, err := o.client.GetDeploymentLabelValues(applabels.ApplicationLabel, applabels.ApplicationLabel)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unable to list applications from deployments")
|
||||
}
|
||||
|
||||
// Filter out any names, as there could be multiple components but within the same application
|
||||
return util.RemoveDuplicates(deploymentAppNames), nil
|
||||
}
|
||||
|
||||
// Exists checks whether the given app exist or not in the list of applications
|
||||
func (o kubernetesClient) Exists(app string) (bool, error) {
|
||||
|
||||
appList, err := o.List()
|
||||
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
for _, appName := range appList {
|
||||
if appName == app {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// Delete the given application by deleting deployments and services instances belonging to this application
|
||||
func (o kubernetesClient) Delete(name string) error {
|
||||
klog.V(4).Infof("Deleting application %q", name)
|
||||
|
||||
labels := applabels.GetLabels(name, false)
|
||||
|
||||
// delete application from cluster
|
||||
err := o.client.Delete(labels, false)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "unable to delete application %s", name)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ComponentList returns the list of components for an application
|
||||
func (o kubernetesClient) ComponentList(name string) ([]component.Component, error) {
|
||||
selector := applabels.GetSelector(name)
|
||||
componentList, err := component.List(o.client, selector)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to get Component list")
|
||||
}
|
||||
return componentList.Items, nil
|
||||
}
|
||||
|
||||
// GetMachineReadableFormat returns resource information in machine readable format
|
||||
func (o kubernetesClient) GetMachineReadableFormat(appName string, projectName string) App {
|
||||
componentList, _ := component.GetComponentNames(o.client, appName)
|
||||
appDef := App{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: appKind,
|
||||
APIVersion: machineoutput.APIVersion,
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: appName,
|
||||
Namespace: projectName,
|
||||
},
|
||||
Spec: AppSpec{
|
||||
Components: componentList,
|
||||
},
|
||||
}
|
||||
return appDef
|
||||
}
|
||||
|
||||
// GetMachineReadableFormatForList returns application list in machine readable format
|
||||
func (o kubernetesClient) GetMachineReadableFormatForList(apps []App) AppList {
|
||||
return AppList{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: appList,
|
||||
APIVersion: machineoutput.APIVersion,
|
||||
},
|
||||
ListMeta: metav1.ListMeta{},
|
||||
Items: apps,
|
||||
}
|
||||
}
|
||||
348
pkg/application/kubernetes_test.go
Normal file
348
pkg/application/kubernetes_test.go
Normal file
@@ -0,0 +1,348 @@
|
||||
package application
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
|
||||
applabels "github.com/redhat-developer/odo/pkg/application/labels"
|
||||
componentlabels "github.com/redhat-developer/odo/pkg/component/labels"
|
||||
"github.com/redhat-developer/odo/pkg/kclient"
|
||||
"github.com/redhat-developer/odo/pkg/machineoutput"
|
||||
"github.com/redhat-developer/odo/pkg/testingutil"
|
||||
"github.com/redhat-developer/odo/pkg/unions"
|
||||
"github.com/redhat-developer/odo/pkg/version"
|
||||
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
ktesting "k8s.io/client-go/testing"
|
||||
)
|
||||
|
||||
func TestList(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
kubclient := kclient.NewMockClientInterface(ctrl)
|
||||
kubclient.EXPECT().GetDeploymentLabelValues("app.kubernetes.io/part-of", "app.kubernetes.io/part-of").Return([]string{"app1", "app3", "app1", "app2"}, nil).AnyTimes()
|
||||
appClient := NewClient(kubclient)
|
||||
result, err := appClient.List()
|
||||
expected := []string{"app1", "app2", "app3"}
|
||||
if err != nil {
|
||||
t.Errorf("Expected nil error, got %s", err)
|
||||
}
|
||||
if !reflect.DeepEqual(result, expected) {
|
||||
t.Errorf("Got %v, expected %v", result, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExists(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
search string
|
||||
result bool
|
||||
err bool
|
||||
}{
|
||||
{
|
||||
name: "not exists",
|
||||
search: "an-app",
|
||||
result: false,
|
||||
err: false,
|
||||
},
|
||||
{
|
||||
name: "exists",
|
||||
search: "app1",
|
||||
result: true,
|
||||
err: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
kubclient := kclient.NewMockClientInterface(ctrl)
|
||||
kubclient.EXPECT().GetDeploymentLabelValues("app.kubernetes.io/part-of", "app.kubernetes.io/part-of").Return([]string{"app1", "app3", "app1", "app2"}, nil).AnyTimes()
|
||||
appClient := NewClient(kubclient)
|
||||
result, err := appClient.Exists(tt.search)
|
||||
if err != nil != tt.err {
|
||||
t.Errorf("Expected %v error, got %v", tt.err, err)
|
||||
}
|
||||
if result != tt.result {
|
||||
t.Errorf("Expected %v, got %v", tt.result, result)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestDelete(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
deleteReturn error
|
||||
expectedErr string
|
||||
}{
|
||||
{
|
||||
name: "kubernetes delete works",
|
||||
deleteReturn: nil,
|
||||
expectedErr: "",
|
||||
},
|
||||
{
|
||||
name: "kubernetes delete fails",
|
||||
deleteReturn: errors.New("an error"),
|
||||
expectedErr: "unable to delete application",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
kubclient := kclient.NewMockClientInterface(ctrl)
|
||||
appClient := NewClient(kubclient)
|
||||
labels := map[string]string{
|
||||
"app.kubernetes.io/part-of": "an-app",
|
||||
}
|
||||
kubclient.EXPECT().Delete(labels, false).Return(tt.deleteReturn).Times(1)
|
||||
|
||||
// kube Delete works
|
||||
err := appClient.Delete("an-app")
|
||||
|
||||
if err == nil && tt.expectedErr != "" {
|
||||
t.Errorf("Expected %v, got no error", tt.expectedErr)
|
||||
return
|
||||
}
|
||||
if err != nil && tt.expectedErr == "" {
|
||||
t.Errorf("Expected no error, got %v", err.Error())
|
||||
return
|
||||
}
|
||||
if err != nil && tt.expectedErr != "" && !strings.Contains(err.Error(), tt.expectedErr) {
|
||||
t.Errorf("Expected error %v, got %v", tt.expectedErr, err.Error())
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestComponentList(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
kubclient := kclient.NewMockClientInterface(ctrl)
|
||||
depList := []appsv1.Deployment{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: map[string]string{
|
||||
"app.kubernetes.io/instance": "a-component",
|
||||
"app.kubernetes.io/part-of": "an-app-name",
|
||||
},
|
||||
Annotations: map[string]string{
|
||||
"odo.dev/project-type": "nodejs",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
kubclient.EXPECT().GetDeploymentFromSelector("app=an-app-name,app.kubernetes.io/managed-by=odo,app.kubernetes.io/part-of=an-app-name").Return(depList, nil).AnyTimes()
|
||||
kubclient.EXPECT().GetCurrentNamespace().Return("my-namespace").AnyTimes()
|
||||
kubclient.EXPECT().GetOneDeployment("a-component", "an-app-name").Return(&depList[0], nil).AnyTimes()
|
||||
ingresses := &unions.KubernetesIngressList{
|
||||
Items: nil,
|
||||
}
|
||||
kubclient.EXPECT().ListIngresses("app.kubernetes.io/instance=a-component,app.kubernetes.io/part-of=an-app-name").Return(ingresses, nil).AnyTimes()
|
||||
kubclient.EXPECT().IsServiceBindingSupported().Return(false, nil).AnyTimes()
|
||||
kubclient.EXPECT().ListSecrets("app.kubernetes.io/instance=a-component,app.kubernetes.io/part-of=an-app-name").Return(nil, nil).AnyTimes()
|
||||
kubclient.EXPECT().ListServices("").Return(nil, nil).AnyTimes()
|
||||
appClient := NewClient(kubclient)
|
||||
|
||||
result, err := appClient.ComponentList("an-app-name")
|
||||
if len(result) != 1 {
|
||||
t.Errorf("expected 1 component in list, got %d", len(result))
|
||||
}
|
||||
component := result[0]
|
||||
if component.Name != "a-component" {
|
||||
t.Errorf("Expected component name %q, got %q", "a-component", component.Name)
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("Expected no error, got %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetMachineReadableFormat(t *testing.T) {
|
||||
type args struct {
|
||||
appName string
|
||||
projectName string
|
||||
active bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want App
|
||||
}{
|
||||
{
|
||||
|
||||
name: "Test Case: machine readable output for application",
|
||||
args: args{
|
||||
appName: "myapp",
|
||||
projectName: "myproject",
|
||||
active: true,
|
||||
},
|
||||
want: App{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: appKind,
|
||||
APIVersion: machineoutput.APIVersion,
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "myapp",
|
||||
Namespace: "myproject",
|
||||
},
|
||||
Spec: AppSpec{
|
||||
Components: []string{"frontend"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
deploymentList := appsv1.DeploymentList{
|
||||
Items: []appsv1.Deployment{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "frontend-myapp",
|
||||
Namespace: "myproject",
|
||||
Labels: map[string]string{
|
||||
applabels.ApplicationLabel: "myapp",
|
||||
componentlabels.ComponentLabel: "frontend",
|
||||
componentlabels.ComponentTypeLabel: "nodejs",
|
||||
applabels.ManagedBy: "odo",
|
||||
applabels.ManagerVersion: version.VERSION,
|
||||
},
|
||||
},
|
||||
Spec: appsv1.DeploymentSpec{
|
||||
Template: corev1.PodTemplateSpec{
|
||||
Spec: corev1.PodSpec{
|
||||
Containers: []corev1.Container{
|
||||
{
|
||||
Name: "dummyContainer",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "backend-app",
|
||||
Namespace: "myproject",
|
||||
Labels: map[string]string{
|
||||
applabels.ApplicationLabel: "app",
|
||||
componentlabels.ComponentLabel: "backend",
|
||||
componentlabels.ComponentTypeLabel: "java",
|
||||
applabels.ManagedBy: "odo",
|
||||
applabels.ManagerVersion: version.VERSION,
|
||||
},
|
||||
},
|
||||
Spec: appsv1.DeploymentSpec{
|
||||
Template: corev1.PodTemplateSpec{
|
||||
Spec: corev1.PodSpec{
|
||||
Containers: []corev1.Container{
|
||||
{
|
||||
Name: "dummyContainer",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Fake the client with the appropriate arguments
|
||||
client, fakeClientSet := kclient.FakeNew()
|
||||
|
||||
// fake the project
|
||||
fakeClientSet.Kubernetes.PrependReactor("get", "projects", func(action ktesting.Action) (handled bool, ret runtime.Object, err error) {
|
||||
return true, &testingutil.FakeOnlyOneExistingProjects().Items[0], nil
|
||||
})
|
||||
|
||||
//fake the deployments
|
||||
fakeClientSet.Kubernetes.PrependReactor("list", "deployments", func(action ktesting.Action) (bool, runtime.Object, error) {
|
||||
return true, &deploymentList, nil
|
||||
})
|
||||
|
||||
for i := range deploymentList.Items {
|
||||
fakeClientSet.Kubernetes.PrependReactor("get", "deployments", func(action ktesting.Action) (bool, runtime.Object, error) {
|
||||
return true, &deploymentList.Items[i], nil
|
||||
})
|
||||
}
|
||||
kclient := NewClient(client)
|
||||
if got := kclient.GetMachineReadableFormat(tt.args.appName, tt.args.projectName); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("GetMachineReadableFormat() = %v,\n want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetMachineReadableFormatForList(t *testing.T) {
|
||||
type args struct {
|
||||
apps []App
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want AppList
|
||||
}{
|
||||
{
|
||||
name: "Test Case: Machine Readable for Application List",
|
||||
args: args{
|
||||
apps: []App{
|
||||
{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: appKind,
|
||||
APIVersion: machineoutput.APIVersion,
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "myapp",
|
||||
},
|
||||
Spec: AppSpec{
|
||||
Components: []string{"frontend"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: AppList{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: appList,
|
||||
APIVersion: machineoutput.APIVersion,
|
||||
},
|
||||
ListMeta: metav1.ListMeta{},
|
||||
Items: []App{
|
||||
{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: appKind,
|
||||
APIVersion: machineoutput.APIVersion,
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "myapp",
|
||||
},
|
||||
Spec: AppSpec{
|
||||
Components: []string{"frontend"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
client, _ := kclient.FakeNew()
|
||||
kclient := NewClient(client)
|
||||
if got := kclient.GetMachineReadableFormatForList(tt.args.apps); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("GetMachineReadableFormatForList() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
122
pkg/application/mock.go
Normal file
122
pkg/application/mock.go
Normal file
@@ -0,0 +1,122 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: pkg/application/application.go
|
||||
|
||||
// Package application is a generated GoMock package.
|
||||
package application
|
||||
|
||||
import (
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
component "github.com/redhat-developer/odo/pkg/component"
|
||||
)
|
||||
|
||||
// MockClient is a mock of Client interface.
|
||||
type MockClient struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockClientMockRecorder
|
||||
}
|
||||
|
||||
// MockClientMockRecorder is the mock recorder for MockClient.
|
||||
type MockClientMockRecorder struct {
|
||||
mock *MockClient
|
||||
}
|
||||
|
||||
// NewMockClient creates a new mock instance.
|
||||
func NewMockClient(ctrl *gomock.Controller) *MockClient {
|
||||
mock := &MockClient{ctrl: ctrl}
|
||||
mock.recorder = &MockClientMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockClient) EXPECT() *MockClientMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// ComponentList mocks base method.
|
||||
func (m *MockClient) ComponentList(name string) ([]component.Component, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ComponentList", name)
|
||||
ret0, _ := ret[0].([]component.Component)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// ComponentList indicates an expected call of ComponentList.
|
||||
func (mr *MockClientMockRecorder) ComponentList(name interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ComponentList", reflect.TypeOf((*MockClient)(nil).ComponentList), name)
|
||||
}
|
||||
|
||||
// Delete mocks base method.
|
||||
func (m *MockClient) Delete(name string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Delete", name)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Delete indicates an expected call of Delete.
|
||||
func (mr *MockClientMockRecorder) Delete(name interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockClient)(nil).Delete), name)
|
||||
}
|
||||
|
||||
// Exists mocks base method.
|
||||
func (m *MockClient) Exists(app string) (bool, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Exists", app)
|
||||
ret0, _ := ret[0].(bool)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// Exists indicates an expected call of Exists.
|
||||
func (mr *MockClientMockRecorder) Exists(app interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Exists", reflect.TypeOf((*MockClient)(nil).Exists), app)
|
||||
}
|
||||
|
||||
// GetMachineReadableFormat mocks base method.
|
||||
func (m *MockClient) GetMachineReadableFormat(appName, projectName string) App {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetMachineReadableFormat", appName, projectName)
|
||||
ret0, _ := ret[0].(App)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// GetMachineReadableFormat indicates an expected call of GetMachineReadableFormat.
|
||||
func (mr *MockClientMockRecorder) GetMachineReadableFormat(appName, projectName interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMachineReadableFormat", reflect.TypeOf((*MockClient)(nil).GetMachineReadableFormat), appName, projectName)
|
||||
}
|
||||
|
||||
// GetMachineReadableFormatForList mocks base method.
|
||||
func (m *MockClient) GetMachineReadableFormatForList(apps []App) AppList {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetMachineReadableFormatForList", apps)
|
||||
ret0, _ := ret[0].(AppList)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// GetMachineReadableFormatForList indicates an expected call of GetMachineReadableFormatForList.
|
||||
func (mr *MockClientMockRecorder) GetMachineReadableFormatForList(apps interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMachineReadableFormatForList", reflect.TypeOf((*MockClient)(nil).GetMachineReadableFormatForList), apps)
|
||||
}
|
||||
|
||||
// List mocks base method.
|
||||
func (m *MockClient) List() ([]string, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "List")
|
||||
ret0, _ := ret[0].([]string)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// List indicates an expected call of List.
|
||||
func (mr *MockClientMockRecorder) List() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "List", reflect.TypeOf((*MockClient)(nil).List))
|
||||
}
|
||||
@@ -4,6 +4,11 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
const (
|
||||
appKind = "Application"
|
||||
appList = "List"
|
||||
)
|
||||
|
||||
// Application
|
||||
type App struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
package kclient
|
||||
|
||||
import (
|
||||
reflect "reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/devfile/library/pkg/devfile/parser/data"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
devfilev1 "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
|
||||
"github.com/devfile/library/pkg/devfile/generator"
|
||||
devfileParser "github.com/devfile/library/pkg/devfile/parser"
|
||||
"github.com/devfile/library/pkg/devfile/parser/data"
|
||||
parsercommon "github.com/devfile/library/pkg/devfile/parser/data/v2/common"
|
||||
"github.com/devfile/library/pkg/testingutil"
|
||||
|
||||
odoTestingUtil "github.com/redhat-developer/odo/pkg/testingutil"
|
||||
"github.com/redhat-developer/odo/pkg/util"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
|
||||
ktesting "k8s.io/client-go/testing"
|
||||
)
|
||||
|
||||
@@ -314,3 +314,47 @@ func TestDeleteDeployment(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetDeploymentLabelValues(t *testing.T) {
|
||||
fkclient, fkclientset := FakeNew()
|
||||
fkclient.Namespace = "default"
|
||||
fkclientset.Kubernetes.PrependReactor("list", "deployments", func(action ktesting.Action) (bool, runtime.Object, error) {
|
||||
depList := appsv1.DeploymentList{
|
||||
Items: []appsv1.Deployment{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: map[string]string{
|
||||
"a-selector": "sel-value",
|
||||
"a-label": "a-value",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: map[string]string{
|
||||
"a-selector": "sel-value-2",
|
||||
"a-label": "a-value-2",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: map[string]string{
|
||||
"other-selector": "sel-value",
|
||||
"a-label": "another-value",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
return true, &depList, nil
|
||||
})
|
||||
result, err := fkclient.GetDeploymentLabelValues("a-label", "a-selector")
|
||||
expected := []string{"a-value", "a-value-2"}
|
||||
if !reflect.DeepEqual(result, expected) {
|
||||
t.Errorf("Expected %v, got %v", expected, result)
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("Expected no error, got %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,9 +5,11 @@ import (
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
kruntime "k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/version"
|
||||
|
||||
"k8s.io/client-go/discovery/fake"
|
||||
ktesting "k8s.io/client-go/testing"
|
||||
)
|
||||
|
||||
func (c *fakeDiscovery) ServerVersion() (*version.Info, error) {
|
||||
@@ -84,3 +86,22 @@ func TestClient_IsSSASupported(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDelete(t *testing.T) {
|
||||
fkclient, fkclientset := FakeNew()
|
||||
fkclient.Namespace = "default"
|
||||
fkclientset.Kubernetes.PrependReactor("delete-collection", "deployments", func(action ktesting.Action) (bool, kruntime.Object, error) {
|
||||
if "a-selector=a-value" != action.(ktesting.DeleteCollectionAction).GetListRestrictions().Labels.String() {
|
||||
return true, nil, errors.New("not found")
|
||||
}
|
||||
return true, nil, nil
|
||||
})
|
||||
|
||||
selectors := map[string]string{
|
||||
"a-selector": "a-value",
|
||||
}
|
||||
err := fkclient.Delete(selectors, false)
|
||||
if err != nil {
|
||||
t.Errorf("Expected no error, got %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,15 +3,11 @@ package application
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
applabels "github.com/redhat-developer/odo/pkg/application/labels"
|
||||
"github.com/redhat-developer/odo/pkg/component"
|
||||
"github.com/redhat-developer/odo/pkg/kclient"
|
||||
"github.com/redhat-developer/odo/pkg/log"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/redhat-developer/odo/pkg/odo/util"
|
||||
odoutil "github.com/redhat-developer/odo/pkg/odo/util"
|
||||
"github.com/redhat-developer/odo/pkg/odo/util/completion"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// RecommendedCommandName is the recommended app command name
|
||||
@@ -50,38 +46,3 @@ func AddApplicationFlag(cmd *cobra.Command) {
|
||||
cmd.Flags().String(util.ApplicationFlagName, "", "Application, defaults to active application")
|
||||
completion.RegisterCommandFlagHandler(cmd, "app", completion.AppCompletionHandler)
|
||||
}
|
||||
|
||||
// printAppInfo will print things which will be deleted
|
||||
func printAppInfo(client kclient.ClientInterface, kClient kclient.ClientInterface, appName string, projectName string) error {
|
||||
var selector string
|
||||
if appName != "" {
|
||||
selector = applabels.GetSelector(appName)
|
||||
}
|
||||
componentList, err := component.List(client, selector)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to get Component list")
|
||||
}
|
||||
|
||||
if len(componentList.Items) != 0 {
|
||||
log.Info("This application has following components that will be deleted")
|
||||
for _, currentComponent := range componentList.Items {
|
||||
log.Info("component named", currentComponent.Name)
|
||||
|
||||
if len(currentComponent.Spec.URL) != 0 {
|
||||
log.Info("This component has following urls that will be deleted with component")
|
||||
for _, u := range currentComponent.Spec.URLSpec {
|
||||
log.Info("URL named", u.GetName(), "with host", u.Spec.Host, "having protocol", u.Spec.Protocol, "at port", u.Spec.Port)
|
||||
}
|
||||
}
|
||||
|
||||
if len(currentComponent.Spec.Storage) != 0 {
|
||||
log.Info("The component has following storages which will be deleted with the component")
|
||||
for _, storage := range currentComponent.Spec.StorageSpec {
|
||||
store := storage
|
||||
log.Info("Storage named", store.GetName(), "of size", store.Spec.Size)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -3,16 +3,18 @@ package application
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
odoUtil "github.com/redhat-developer/odo/pkg/odo/util"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/redhat-developer/odo/pkg/application"
|
||||
"github.com/redhat-developer/odo/pkg/kclient"
|
||||
"github.com/redhat-developer/odo/pkg/log"
|
||||
"github.com/redhat-developer/odo/pkg/odo/cli/project"
|
||||
"github.com/redhat-developer/odo/pkg/odo/cli/ui"
|
||||
"github.com/redhat-developer/odo/pkg/odo/cmdline"
|
||||
"github.com/redhat-developer/odo/pkg/odo/genericclioptions"
|
||||
odoUtil "github.com/redhat-developer/odo/pkg/odo/util"
|
||||
"github.com/redhat-developer/odo/pkg/odo/util/completion"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
ktemplates "k8s.io/kubectl/pkg/util/templates"
|
||||
)
|
||||
|
||||
@@ -28,6 +30,9 @@ type DeleteOptions struct {
|
||||
// Context
|
||||
*genericclioptions.Context
|
||||
|
||||
// Clients
|
||||
appClient application.Client
|
||||
|
||||
// Parameters
|
||||
appName string
|
||||
|
||||
@@ -36,8 +41,10 @@ type DeleteOptions struct {
|
||||
}
|
||||
|
||||
// NewDeleteOptions creates a new DeleteOptions instance
|
||||
func NewDeleteOptions() *DeleteOptions {
|
||||
return &DeleteOptions{}
|
||||
func NewDeleteOptions(appClient application.Client) *DeleteOptions {
|
||||
return &DeleteOptions{
|
||||
appClient: appClient,
|
||||
}
|
||||
}
|
||||
|
||||
// Complete completes DeleteOptions after they've been created
|
||||
@@ -51,7 +58,6 @@ func (o *DeleteOptions) Complete(cmdline cmdline.Cmdline, args []string) (err er
|
||||
// If app name passed, consider it for deletion
|
||||
o.appName = args[0]
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -61,7 +67,7 @@ func (o *DeleteOptions) Validate() (err error) {
|
||||
return odoUtil.ThrowContextError()
|
||||
}
|
||||
|
||||
exist, err := application.Exists(o.appName, o.KClient)
|
||||
exist, err := o.appClient.Exists(o.appName)
|
||||
if !exist {
|
||||
return fmt.Errorf("%s app does not exists", o.appName)
|
||||
}
|
||||
@@ -70,22 +76,18 @@ func (o *DeleteOptions) Validate() (err error) {
|
||||
|
||||
// Run contains the logic for the odo command
|
||||
func (o *DeleteOptions) Run() (err error) {
|
||||
if log.IsJSON() {
|
||||
err = application.Delete(o.KClient, o.appName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
if o.IsJSON() {
|
||||
return o.appClient.Delete(o.appName)
|
||||
}
|
||||
|
||||
// Print App Information which will be deleted
|
||||
err = printAppInfo(o.KClient, o.KClient, o.appName, o.GetProject())
|
||||
err = printAppInfo(o.appClient, o.appName, o.GetProject())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if o.forceFlag || ui.Proceed(fmt.Sprintf("Are you sure you want to delete the application: %v from project: %v", o.appName, o.GetProject())) {
|
||||
err = application.Delete(o.KClient, o.appName)
|
||||
err = o.appClient.Delete(o.appName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -93,12 +95,44 @@ func (o *DeleteOptions) Run() (err error) {
|
||||
} else {
|
||||
log.Infof("Aborting deletion of application: %v", o.appName)
|
||||
}
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
// printAppInfo will print information about the app requested for deletion
|
||||
func printAppInfo(appClient application.Client, appName string, projectName string) error {
|
||||
components, err := appClient.ComponentList(appName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(components) != 0 {
|
||||
log.Info("This application has following components that will be deleted")
|
||||
for _, currentComponent := range components {
|
||||
log.Info("component named", currentComponent.Name)
|
||||
|
||||
if len(currentComponent.Spec.URL) != 0 {
|
||||
log.Info("This component has following urls that will be deleted with component")
|
||||
for _, u := range currentComponent.Spec.URLSpec {
|
||||
log.Info("URL named", u.GetName(), "with host", u.Spec.Host, "having protocol", u.Spec.Protocol, "at port", u.Spec.Port)
|
||||
}
|
||||
}
|
||||
|
||||
if len(currentComponent.Spec.Storage) != 0 {
|
||||
log.Info("The component has following storages which will be deleted with the component")
|
||||
for _, storage := range currentComponent.Spec.StorageSpec {
|
||||
store := storage
|
||||
log.Info("Storage named", store.GetName(), "of size", store.Spec.Size)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewCmdDelete implements the odo command.
|
||||
func NewCmdDelete(name, fullName string) *cobra.Command {
|
||||
o := NewDeleteOptions()
|
||||
// The error is not handled at this point, it will be handled during Context creation
|
||||
kubclient, _ := kclient.New()
|
||||
o := NewDeleteOptions(application.NewClient(kubclient))
|
||||
command := &cobra.Command{
|
||||
Use: name,
|
||||
Short: "Delete the given application",
|
||||
|
||||
203
pkg/odo/cli/application/delete_test.go
Normal file
203
pkg/odo/cli/application/delete_test.go
Normal file
@@ -0,0 +1,203 @@
|
||||
package application
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
|
||||
"github.com/redhat-developer/odo/pkg/application"
|
||||
"github.com/redhat-developer/odo/pkg/envinfo"
|
||||
"github.com/redhat-developer/odo/pkg/kclient"
|
||||
"github.com/redhat-developer/odo/pkg/odo/cmdline"
|
||||
"github.com/redhat-developer/odo/pkg/testingutil/filesystem"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func TestDelete(t *testing.T) {
|
||||
|
||||
prefixDir, err := os.MkdirTemp(os.TempDir(), "unittests-")
|
||||
if err != nil {
|
||||
t.Errorf("Error creating temp directory for tests")
|
||||
return
|
||||
}
|
||||
workingDir := filepath.Join(prefixDir, "myapp")
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
populateWorkingDir func(fs filesystem.Filesystem)
|
||||
args []string
|
||||
existingApps []string
|
||||
wantAppName string
|
||||
wantErrValidate string
|
||||
}{
|
||||
{
|
||||
name: "default app",
|
||||
populateWorkingDir: func(fs filesystem.Filesystem) {
|
||||
_ = fs.MkdirAll(filepath.Join(prefixDir, "myapp", ".odo", "env"), 0755)
|
||||
env, err := envinfo.NewEnvSpecificInfo(filepath.Join(prefixDir, "myapp"))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_ = env.SetComponentSettings(envinfo.ComponentSettings{
|
||||
Name: "a-name",
|
||||
Project: "a-project",
|
||||
AppName: "an-app-name",
|
||||
})
|
||||
},
|
||||
existingApps: []string{"an-app-name", "another-app-name"},
|
||||
wantAppName: "an-app-name",
|
||||
},
|
||||
{
|
||||
name: "app from args",
|
||||
populateWorkingDir: func(fs filesystem.Filesystem) {
|
||||
_ = fs.MkdirAll(filepath.Join(prefixDir, "myapp", ".odo", "env"), 0755)
|
||||
env, err := envinfo.NewEnvSpecificInfo(filepath.Join(prefixDir, "myapp"))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_ = env.SetComponentSettings(envinfo.ComponentSettings{
|
||||
Name: "a-name",
|
||||
Project: "a-project",
|
||||
AppName: "an-app-name",
|
||||
})
|
||||
},
|
||||
args: []string{"another-app-name"},
|
||||
existingApps: []string{"an-app-name", "another-app-name"},
|
||||
wantAppName: "another-app-name",
|
||||
},
|
||||
{
|
||||
name: "empty app name",
|
||||
populateWorkingDir: func(fs filesystem.Filesystem) {
|
||||
_ = fs.MkdirAll(filepath.Join(prefixDir, "myapp", ".odo", "env"), 0755)
|
||||
env, err := envinfo.NewEnvSpecificInfo(filepath.Join(prefixDir, "myapp"))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_ = env.SetComponentSettings(envinfo.ComponentSettings{
|
||||
Name: "a-name",
|
||||
Project: "a-project",
|
||||
AppName: "",
|
||||
})
|
||||
},
|
||||
existingApps: []string{"an-app-name", "another-app-name"},
|
||||
wantAppName: "",
|
||||
wantErrValidate: "Please specify the application name and project name",
|
||||
},
|
||||
{
|
||||
name: "non existing app name",
|
||||
populateWorkingDir: func(fs filesystem.Filesystem) {
|
||||
_ = fs.MkdirAll(filepath.Join(prefixDir, "myapp", ".odo", "env"), 0755)
|
||||
env, err := envinfo.NewEnvSpecificInfo(filepath.Join(prefixDir, "myapp"))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_ = env.SetComponentSettings(envinfo.ComponentSettings{
|
||||
Name: "a-name",
|
||||
Project: "a-project",
|
||||
AppName: "an-app-name",
|
||||
})
|
||||
},
|
||||
args: []string{"an-unknown-app-name"},
|
||||
existingApps: []string{"an-app-name", "another-app-name"},
|
||||
wantAppName: "an-unknown-app-name",
|
||||
wantErrValidate: " app does not exists",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// the first one is to cleanup the directory before execution (in case there are remaining files from a previous execution)
|
||||
os.RemoveAll(prefixDir)
|
||||
// the second one to cleanup after execution
|
||||
defer os.RemoveAll(prefixDir)
|
||||
|
||||
// Fake Cobra
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
cmdline := cmdline.NewMockCmdline(ctrl)
|
||||
|
||||
// Fake odo Kube client
|
||||
kclient := kclient.NewMockClientInterface(ctrl)
|
||||
|
||||
/* Mocks for Complete */
|
||||
cmdline.EXPECT().GetWorkingDirectory().Return(workingDir, nil).AnyTimes()
|
||||
cmdline.EXPECT().CheckIfConfigurationNeeded().Return(false, nil).AnyTimes()
|
||||
cmdline.EXPECT().FlagValueIfSet("project").Return("").AnyTimes()
|
||||
cmdline.EXPECT().FlagValueIfSet("app").Return("").AnyTimes()
|
||||
cmdline.EXPECT().FlagValueIfSet("component").Return("").AnyTimes()
|
||||
cmdline.EXPECT().FlagValueIfSet("o").Return("").AnyTimes()
|
||||
cmdline.EXPECT().GetKubeClient().Return(kclient, nil).AnyTimes()
|
||||
|
||||
ns := &corev1.Namespace{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "a-project",
|
||||
},
|
||||
}
|
||||
kclient.EXPECT().GetNamespaceNormal("a-project").Return(ns, nil).AnyTimes()
|
||||
kclient.EXPECT().SetNamespace("a-project").AnyTimes()
|
||||
|
||||
tt.populateWorkingDir(filesystem.DefaultFs{})
|
||||
|
||||
/* Mocks for Complete */
|
||||
appClient := application.NewMockClient(ctrl)
|
||||
appClient.EXPECT().Exists(tt.wantAppName).Return(func() bool {
|
||||
for _, app := range tt.existingApps {
|
||||
if tt.wantAppName == app {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}(), nil).AnyTimes()
|
||||
appClient.EXPECT().ComponentList(tt.wantAppName).AnyTimes()
|
||||
opts := NewDeleteOptions(appClient)
|
||||
// Force to disable interactive confirmation
|
||||
opts.forceFlag = true
|
||||
|
||||
/* COMPLETE */
|
||||
err := opts.Complete(cmdline, tt.args)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Expected nil error, got %s", err)
|
||||
return
|
||||
}
|
||||
if opts.appName != tt.wantAppName {
|
||||
t.Errorf("Got appName %q, expected %q", opts.appName, tt.wantAppName)
|
||||
}
|
||||
|
||||
/* VALIDATE */
|
||||
err = opts.Validate()
|
||||
|
||||
if err == nil && tt.wantErrValidate != "" {
|
||||
t.Errorf("Expected %v, got no error", tt.wantErrValidate)
|
||||
return
|
||||
}
|
||||
if err != nil && tt.wantErrValidate == "" {
|
||||
t.Errorf("Expected no error, got %v", err.Error())
|
||||
return
|
||||
}
|
||||
if err != nil && tt.wantErrValidate != "" && !strings.Contains(err.Error(), tt.wantErrValidate) {
|
||||
t.Errorf("Expected error %v, got %v", tt.wantErrValidate, err.Error())
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
/* Mocks for Run */
|
||||
kclient.EXPECT().GetDeploymentFromSelector(fmt.Sprintf("app=%s,app.kubernetes.io/managed-by=odo,app.kubernetes.io/part-of=%s", tt.wantAppName, tt.wantAppName)).AnyTimes()
|
||||
appClient.EXPECT().Delete(tt.wantAppName).Times(1)
|
||||
|
||||
/* RUN */
|
||||
err = opts.Run()
|
||||
if err != nil {
|
||||
t.Errorf("Expected nil err, got %s", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -3,18 +3,17 @@ package application
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
applabels "github.com/redhat-developer/odo/pkg/application/labels"
|
||||
"github.com/redhat-developer/odo/pkg/odo/cmdline"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/redhat-developer/odo/pkg/application"
|
||||
"github.com/redhat-developer/odo/pkg/component"
|
||||
"github.com/redhat-developer/odo/pkg/log"
|
||||
"github.com/redhat-developer/odo/pkg/kclient"
|
||||
"github.com/redhat-developer/odo/pkg/machineoutput"
|
||||
"github.com/redhat-developer/odo/pkg/odo/cli/project"
|
||||
"github.com/redhat-developer/odo/pkg/odo/cmdline"
|
||||
"github.com/redhat-developer/odo/pkg/odo/genericclioptions"
|
||||
"github.com/redhat-developer/odo/pkg/odo/util"
|
||||
"github.com/redhat-developer/odo/pkg/odo/util/completion"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
ktemplates "k8s.io/kubectl/pkg/util/templates"
|
||||
)
|
||||
|
||||
@@ -30,13 +29,18 @@ type DescribeOptions struct {
|
||||
// Context
|
||||
*genericclioptions.Context
|
||||
|
||||
// Clients
|
||||
appClient application.Client
|
||||
|
||||
// Parameters
|
||||
appName string
|
||||
}
|
||||
|
||||
// NewDescribeOptions creates a new DescribeOptions instance
|
||||
func NewDescribeOptions() *DescribeOptions {
|
||||
return &DescribeOptions{}
|
||||
func NewDescribeOptions(appClient application.Client) *DescribeOptions {
|
||||
return &DescribeOptions{
|
||||
appClient: appClient,
|
||||
}
|
||||
}
|
||||
|
||||
// Complete completes DescribeOptions after they've been created
|
||||
@@ -57,11 +61,8 @@ func (o *DescribeOptions) Validate() (err error) {
|
||||
if o.Context.GetProject() == "" || o.appName == "" {
|
||||
return util.ThrowContextError()
|
||||
}
|
||||
if o.appName == "" {
|
||||
return fmt.Errorf("There's no active application in project: %v", o.GetProject())
|
||||
}
|
||||
|
||||
exist, err := application.Exists(o.appName, o.KClient)
|
||||
exist, err := o.appClient.Exists(o.appName)
|
||||
if !exist {
|
||||
return fmt.Errorf("%s app does not exists", o.appName)
|
||||
}
|
||||
@@ -70,42 +71,40 @@ func (o *DescribeOptions) Validate() (err error) {
|
||||
|
||||
// Run contains the logic for the odo command
|
||||
func (o *DescribeOptions) Run() (err error) {
|
||||
if log.IsJSON() {
|
||||
appDef := application.GetMachineReadableFormat(o.KClient, o.appName, o.GetProject())
|
||||
if o.IsJSON() {
|
||||
appDef := o.appClient.GetMachineReadableFormat(o.appName, o.GetProject())
|
||||
machineoutput.OutputSuccess(appDef)
|
||||
} else {
|
||||
var selector string
|
||||
if o.appName != "" {
|
||||
selector = applabels.GetSelector(o.appName)
|
||||
}
|
||||
componentList, err := component.List(o.KClient, selector)
|
||||
return nil
|
||||
}
|
||||
|
||||
componentList, err := o.appClient.ComponentList(o.appName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(componentList) == 0 {
|
||||
fmt.Printf("Application %s has no components or services deployed.", o.appName)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("Application Name: %s has %v component(s):\n--------------------------------------\n",
|
||||
o.appName, len(componentList))
|
||||
for _, currentComponent := range componentList {
|
||||
err := util.PrintComponentInfo(o.KClient, currentComponent.Name, currentComponent, o.appName, o.GetProject())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(componentList.Items) == 0 {
|
||||
fmt.Printf("Application %s has no components or services deployed.", o.appName)
|
||||
} else {
|
||||
fmt.Printf("Application Name: %s has %v component(s):\n--------------------------------------\n",
|
||||
o.appName, len(componentList.Items))
|
||||
if len(componentList.Items) > 0 {
|
||||
for _, currentComponent := range componentList.Items {
|
||||
err := util.PrintComponentInfo(o.KClient, currentComponent.Name, currentComponent, o.appName, o.GetProject())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println("--------------------------------------")
|
||||
}
|
||||
}
|
||||
}
|
||||
fmt.Println("--------------------------------------")
|
||||
}
|
||||
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewCmdDescribe implements the odo command.
|
||||
func NewCmdDescribe(name, fullName string) *cobra.Command {
|
||||
o := NewDescribeOptions()
|
||||
// The error is not handled at this point, it will be handled during Context creation
|
||||
kubclient, _ := kclient.New()
|
||||
o := NewDescribeOptions(application.NewClient(kubclient))
|
||||
command := &cobra.Command{
|
||||
Use: fmt.Sprintf("%s [application_name]", name),
|
||||
Short: "Describe the given application",
|
||||
|
||||
197
pkg/odo/cli/application/describe_test.go
Normal file
197
pkg/odo/cli/application/describe_test.go
Normal file
@@ -0,0 +1,197 @@
|
||||
package application
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
|
||||
"github.com/redhat-developer/odo/pkg/application"
|
||||
"github.com/redhat-developer/odo/pkg/envinfo"
|
||||
"github.com/redhat-developer/odo/pkg/kclient"
|
||||
"github.com/redhat-developer/odo/pkg/odo/cmdline"
|
||||
"github.com/redhat-developer/odo/pkg/testingutil/filesystem"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func TestDescribe(t *testing.T) {
|
||||
|
||||
prefixDir, err := os.MkdirTemp(os.TempDir(), "unittests-")
|
||||
if err != nil {
|
||||
t.Errorf("Error creating temp directory for tests")
|
||||
return
|
||||
}
|
||||
workingDir := filepath.Join(prefixDir, "myapp")
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
populateWorkingDir func(fs filesystem.Filesystem)
|
||||
args []string
|
||||
existingApps []string
|
||||
wantAppName string
|
||||
wantErrValidate string
|
||||
}{
|
||||
{
|
||||
name: "default app",
|
||||
populateWorkingDir: func(fs filesystem.Filesystem) {
|
||||
_ = fs.MkdirAll(filepath.Join(prefixDir, "myapp", ".odo", "env"), 0755)
|
||||
env, err := envinfo.NewEnvSpecificInfo(filepath.Join(prefixDir, "myapp"))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_ = env.SetComponentSettings(envinfo.ComponentSettings{
|
||||
Name: "a-name",
|
||||
Project: "a-project",
|
||||
AppName: "an-app-name",
|
||||
})
|
||||
},
|
||||
existingApps: []string{"an-app-name", "another-app-name"},
|
||||
wantAppName: "an-app-name",
|
||||
},
|
||||
{
|
||||
name: "app from args",
|
||||
populateWorkingDir: func(fs filesystem.Filesystem) {
|
||||
_ = fs.MkdirAll(filepath.Join(prefixDir, "myapp", ".odo", "env"), 0755)
|
||||
env, err := envinfo.NewEnvSpecificInfo(filepath.Join(prefixDir, "myapp"))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_ = env.SetComponentSettings(envinfo.ComponentSettings{
|
||||
Name: "a-name",
|
||||
Project: "a-project",
|
||||
AppName: "an-app-name",
|
||||
})
|
||||
},
|
||||
args: []string{"another-app-name"},
|
||||
existingApps: []string{"an-app-name", "another-app-name"},
|
||||
wantAppName: "another-app-name",
|
||||
},
|
||||
{
|
||||
name: "empty app name",
|
||||
populateWorkingDir: func(fs filesystem.Filesystem) {
|
||||
_ = fs.MkdirAll(filepath.Join(prefixDir, "myapp", ".odo", "env"), 0755)
|
||||
env, err := envinfo.NewEnvSpecificInfo(filepath.Join(prefixDir, "myapp"))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_ = env.SetComponentSettings(envinfo.ComponentSettings{
|
||||
Name: "a-name",
|
||||
Project: "a-project",
|
||||
AppName: "",
|
||||
})
|
||||
},
|
||||
existingApps: []string{"an-app-name", "another-app-name"},
|
||||
wantAppName: "",
|
||||
wantErrValidate: "Please specify the application name and project name",
|
||||
},
|
||||
{
|
||||
name: "non existing app name",
|
||||
populateWorkingDir: func(fs filesystem.Filesystem) {
|
||||
_ = fs.MkdirAll(filepath.Join(prefixDir, "myapp", ".odo", "env"), 0755)
|
||||
env, err := envinfo.NewEnvSpecificInfo(filepath.Join(prefixDir, "myapp"))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_ = env.SetComponentSettings(envinfo.ComponentSettings{
|
||||
Name: "a-name",
|
||||
Project: "a-project",
|
||||
AppName: "an-app-name",
|
||||
})
|
||||
},
|
||||
args: []string{"an-unknown-app-name"},
|
||||
existingApps: []string{"an-app-name", "another-app-name"},
|
||||
wantAppName: "an-unknown-app-name",
|
||||
wantErrValidate: " app does not exists",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// the first one is to cleanup the directory before execution (in case there are remaining files from a previous execution)
|
||||
os.RemoveAll(prefixDir)
|
||||
// the second one to cleanup after execution
|
||||
defer os.RemoveAll(prefixDir)
|
||||
|
||||
// Fake Cobra
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
cmdline := cmdline.NewMockCmdline(ctrl)
|
||||
|
||||
// Fake odo Kube client
|
||||
kclient := kclient.NewMockClientInterface(ctrl)
|
||||
|
||||
/* Mocks for Complete */
|
||||
cmdline.EXPECT().GetWorkingDirectory().Return(workingDir, nil).AnyTimes()
|
||||
cmdline.EXPECT().CheckIfConfigurationNeeded().Return(false, nil).AnyTimes()
|
||||
cmdline.EXPECT().FlagValueIfSet("project").Return("").AnyTimes()
|
||||
cmdline.EXPECT().FlagValueIfSet("app").Return("").AnyTimes()
|
||||
cmdline.EXPECT().FlagValueIfSet("component").Return("").AnyTimes()
|
||||
cmdline.EXPECT().FlagValueIfSet("o").Return("").AnyTimes()
|
||||
cmdline.EXPECT().GetKubeClient().Return(kclient, nil).AnyTimes()
|
||||
|
||||
ns := &corev1.Namespace{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "a-project",
|
||||
},
|
||||
}
|
||||
kclient.EXPECT().GetNamespaceNormal("a-project").Return(ns, nil).AnyTimes()
|
||||
kclient.EXPECT().SetNamespace("a-project").AnyTimes()
|
||||
|
||||
tt.populateWorkingDir(filesystem.DefaultFs{})
|
||||
|
||||
/* Mocks for Complete */
|
||||
appClient := application.NewMockClient(ctrl)
|
||||
appClient.EXPECT().Exists(tt.wantAppName).Return(func() bool {
|
||||
for _, app := range tt.existingApps {
|
||||
if tt.wantAppName == app {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}(), nil).AnyTimes()
|
||||
opts := NewDescribeOptions(appClient)
|
||||
|
||||
/* COMPLETE */
|
||||
err := opts.Complete(cmdline, tt.args)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if opts.appName != tt.wantAppName {
|
||||
t.Errorf("Got appName %q, expected %q", opts.appName, tt.wantAppName)
|
||||
}
|
||||
|
||||
/* VALIDATE */
|
||||
err = opts.Validate()
|
||||
|
||||
if err == nil && tt.wantErrValidate != "" {
|
||||
t.Errorf("Expected %v, got no error", tt.wantErrValidate)
|
||||
return
|
||||
}
|
||||
if err != nil && tt.wantErrValidate == "" {
|
||||
t.Errorf("Expected no error, got %v", err.Error())
|
||||
return
|
||||
}
|
||||
if err != nil && tt.wantErrValidate != "" && !strings.Contains(err.Error(), tt.wantErrValidate) {
|
||||
t.Errorf("Expected error %v, got %v", tt.wantErrValidate, err.Error())
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
/* Mocks for Run */
|
||||
appClient.EXPECT().ComponentList(tt.wantAppName)
|
||||
|
||||
/* RUN */
|
||||
err = opts.Run()
|
||||
if err != nil {
|
||||
t.Errorf("Expected nil err, got %s", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -5,14 +5,17 @@ import (
|
||||
"os"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/redhat-developer/odo/pkg/application"
|
||||
"github.com/redhat-developer/odo/pkg/kclient"
|
||||
"github.com/redhat-developer/odo/pkg/log"
|
||||
"github.com/redhat-developer/odo/pkg/machineoutput"
|
||||
"github.com/redhat-developer/odo/pkg/odo/cli/project"
|
||||
"github.com/redhat-developer/odo/pkg/odo/cmdline"
|
||||
"github.com/redhat-developer/odo/pkg/odo/genericclioptions"
|
||||
"github.com/redhat-developer/odo/pkg/odo/util"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
ktemplates "k8s.io/kubectl/pkg/util/templates"
|
||||
)
|
||||
|
||||
@@ -30,17 +33,22 @@ var (
|
||||
type ListOptions struct {
|
||||
// Context
|
||||
*genericclioptions.Context
|
||||
|
||||
// Clients
|
||||
appClient application.Client
|
||||
}
|
||||
|
||||
// NewListOptions creates a new ListOptions instance
|
||||
func NewListOptions() *ListOptions {
|
||||
return &ListOptions{}
|
||||
func NewListOptions(appClient application.Client) *ListOptions {
|
||||
return &ListOptions{
|
||||
appClient: appClient,
|
||||
}
|
||||
}
|
||||
|
||||
// Complete completes ListOptions after they've been created
|
||||
func (o *ListOptions) Complete(cmdline cmdline.Cmdline, args []string) (err error) {
|
||||
o.Context, err = genericclioptions.New(genericclioptions.NewCreateParameters(cmdline))
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
// Validate validates the ListOptions based on completed values
|
||||
@@ -54,52 +62,55 @@ func (o *ListOptions) Validate() (err error) {
|
||||
|
||||
// Run contains the logic for the odo command
|
||||
func (o *ListOptions) Run() (err error) {
|
||||
apps, err := application.List(o.KClient)
|
||||
apps, err := o.appClient.List()
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to get list of applications: %v", err)
|
||||
}
|
||||
|
||||
if len(apps) > 0 {
|
||||
|
||||
if log.IsJSON() {
|
||||
var appList []application.App
|
||||
for _, app := range apps {
|
||||
appDef := application.GetMachineReadableFormat(o.KClient, app, o.GetProject())
|
||||
appList = append(appList, appDef)
|
||||
}
|
||||
|
||||
appListDef := application.GetMachineReadableFormatForList(appList)
|
||||
machineoutput.OutputSuccess(appListDef)
|
||||
|
||||
} else {
|
||||
log.Infof("The project '%v' has the following applications:", o.GetProject())
|
||||
tabWriter := tabwriter.NewWriter(os.Stdout, 5, 2, 3, ' ', tabwriter.TabIndent)
|
||||
_, err := fmt.Fprintln(tabWriter, "NAME")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, app := range apps {
|
||||
_, err := fmt.Fprintln(tabWriter, app)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return tabWriter.Flush()
|
||||
}
|
||||
} else {
|
||||
if log.IsJSON() {
|
||||
apps := application.GetMachineReadableFormatForList([]application.App{})
|
||||
if len(apps) == 0 {
|
||||
if o.IsJSON() {
|
||||
apps := o.appClient.GetMachineReadableFormatForList([]application.App{})
|
||||
machineoutput.OutputSuccess(apps)
|
||||
} else {
|
||||
log.Infof("There are no applications deployed in the project '%v'", o.GetProject())
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Infof("There are no applications deployed in the project '%v'", o.GetProject())
|
||||
return nil
|
||||
}
|
||||
|
||||
if o.IsJSON() {
|
||||
var appList []application.App
|
||||
for _, app := range apps {
|
||||
appDef := o.appClient.GetMachineReadableFormat(app, o.GetProject())
|
||||
appList = append(appList, appDef)
|
||||
}
|
||||
|
||||
appListDef := o.appClient.GetMachineReadableFormatForList(appList)
|
||||
machineoutput.OutputSuccess(appListDef)
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Infof("The project '%v' has the following applications:", o.GetProject())
|
||||
tabWriter := tabwriter.NewWriter(os.Stdout, 5, 2, 3, ' ', tabwriter.TabIndent)
|
||||
_, err = fmt.Fprintln(tabWriter, "NAME")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, app := range apps {
|
||||
_, err := fmt.Fprintln(tabWriter, app)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return
|
||||
return tabWriter.Flush()
|
||||
|
||||
}
|
||||
|
||||
// NewCmdList implements the odo command.
|
||||
func NewCmdList(name, fullName string) *cobra.Command {
|
||||
o := NewListOptions()
|
||||
// The error is not handled at this point, it will be handled during Context creation
|
||||
kubclient, _ := kclient.New()
|
||||
o := NewListOptions(application.NewClient(kubclient))
|
||||
command := &cobra.Command{
|
||||
Use: name,
|
||||
Short: "List all applications in the current project",
|
||||
|
||||
149
pkg/odo/cli/application/list_test.go
Normal file
149
pkg/odo/cli/application/list_test.go
Normal file
@@ -0,0 +1,149 @@
|
||||
package application
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
|
||||
"github.com/redhat-developer/odo/pkg/application"
|
||||
"github.com/redhat-developer/odo/pkg/envinfo"
|
||||
"github.com/redhat-developer/odo/pkg/kclient"
|
||||
"github.com/redhat-developer/odo/pkg/odo/cmdline"
|
||||
"github.com/redhat-developer/odo/pkg/testingutil/filesystem"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func TestList(t *testing.T) {
|
||||
|
||||
prefixDir, err := os.MkdirTemp(os.TempDir(), "unittests-")
|
||||
if err != nil {
|
||||
t.Errorf("Error creating temp directory for tests")
|
||||
return
|
||||
}
|
||||
workingDir := filepath.Join(prefixDir, "myapp")
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
populateWorkingDir func(fs filesystem.Filesystem)
|
||||
currentNamespace string
|
||||
wantErrValidate string
|
||||
}{
|
||||
{
|
||||
name: "default app",
|
||||
populateWorkingDir: func(fs filesystem.Filesystem) {
|
||||
_ = fs.MkdirAll(filepath.Join(prefixDir, "myapp", ".odo", "env"), 0755)
|
||||
env, err := envinfo.NewEnvSpecificInfo(filepath.Join(prefixDir, "myapp"))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_ = env.SetComponentSettings(envinfo.ComponentSettings{
|
||||
Name: "a-name",
|
||||
Project: "a-project",
|
||||
AppName: "an-app-name",
|
||||
})
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "empty project name",
|
||||
populateWorkingDir: func(fs filesystem.Filesystem) {
|
||||
_ = fs.MkdirAll(filepath.Join(prefixDir, "myapp", ".odo", "env"), 0755)
|
||||
env, err := envinfo.NewEnvSpecificInfo(filepath.Join(prefixDir, "myapp"))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_ = env.SetComponentSettings(envinfo.ComponentSettings{
|
||||
Name: "a-name",
|
||||
Project: "",
|
||||
AppName: "an-app-name",
|
||||
})
|
||||
},
|
||||
currentNamespace: "",
|
||||
wantErrValidate: "Please specify the application name and project name",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// the first one is to cleanup the directory before execution (in case there are remaining files from a previous execution)
|
||||
os.RemoveAll(prefixDir)
|
||||
// the second one to cleanup after execution
|
||||
defer os.RemoveAll(prefixDir)
|
||||
|
||||
// Fake Cobra
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
cmdline := cmdline.NewMockCmdline(ctrl)
|
||||
|
||||
// Fake odo Kube client
|
||||
kclient := kclient.NewMockClientInterface(ctrl)
|
||||
|
||||
/* Mocks for Complete */
|
||||
cmdline.EXPECT().GetWorkingDirectory().Return(workingDir, nil).AnyTimes()
|
||||
cmdline.EXPECT().CheckIfConfigurationNeeded().Return(false, nil).AnyTimes()
|
||||
cmdline.EXPECT().FlagValueIfSet("project").Return("").AnyTimes()
|
||||
cmdline.EXPECT().FlagValueIfSet("app").Return("").AnyTimes()
|
||||
cmdline.EXPECT().FlagValueIfSet("component").Return("").AnyTimes()
|
||||
cmdline.EXPECT().FlagValueIfSet("o").Return("").AnyTimes()
|
||||
cmdline.EXPECT().GetName().Return("list").AnyTimes()
|
||||
cmdline.EXPECT().GetParentName().Return("application").AnyTimes()
|
||||
cmdline.EXPECT().GetKubeClient().Return(kclient, nil).AnyTimes()
|
||||
|
||||
ns := &corev1.Namespace{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "a-project",
|
||||
},
|
||||
}
|
||||
kclient.EXPECT().GetNamespaceNormal("a-project").Return(ns, nil).AnyTimes()
|
||||
kclient.EXPECT().GetNamespaceNormal("").Return(nil, nil).AnyTimes()
|
||||
kclient.EXPECT().SetNamespace("a-project").AnyTimes()
|
||||
kclient.EXPECT().SetNamespace("").AnyTimes()
|
||||
kclient.EXPECT().GetCurrentNamespace().Return(tt.currentNamespace).AnyTimes()
|
||||
|
||||
tt.populateWorkingDir(filesystem.DefaultFs{})
|
||||
|
||||
/* Mocks for Complete */
|
||||
appClient := application.NewMockClient(ctrl)
|
||||
opts := NewListOptions(appClient)
|
||||
|
||||
/* COMPLETE */
|
||||
err := opts.Complete(cmdline, []string{})
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
/* VALIDATE */
|
||||
err = opts.Validate()
|
||||
|
||||
if err == nil && tt.wantErrValidate != "" {
|
||||
t.Errorf("Expected %v, got no error", tt.wantErrValidate)
|
||||
return
|
||||
}
|
||||
if err != nil && tt.wantErrValidate == "" {
|
||||
t.Errorf("Expected no error, got %v", err.Error())
|
||||
return
|
||||
}
|
||||
if err != nil && tt.wantErrValidate != "" && !strings.Contains(err.Error(), tt.wantErrValidate) {
|
||||
t.Errorf("Expected error %v, got %v", tt.wantErrValidate, err.Error())
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
/* Mocks for Run */
|
||||
appClient.EXPECT().List().Times(1)
|
||||
|
||||
/* RUN */
|
||||
err = opts.Run()
|
||||
if err != nil {
|
||||
t.Errorf("Expected nil err, got %s", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -19,18 +19,27 @@ import (
|
||||
|
||||
// CommonPushOptions has data needed for all pushes
|
||||
type CommonPushOptions struct {
|
||||
// Context
|
||||
*genericclioptions.Context
|
||||
|
||||
// Clients
|
||||
prjClient project.Client
|
||||
|
||||
//Flags
|
||||
// TODO(feloy) Fixme
|
||||
showFlag bool //nolint:structcheck
|
||||
componentContext string
|
||||
configFlag bool
|
||||
sourceFlag bool
|
||||
EnvSpecificInfo *envinfo.EnvSpecificInfo
|
||||
*genericclioptions.Context
|
||||
|
||||
EnvSpecificInfo *envinfo.EnvSpecificInfo
|
||||
}
|
||||
|
||||
// NewCommonPushOptions instantiates a commonPushOptions object
|
||||
func NewCommonPushOptions() *CommonPushOptions {
|
||||
return &CommonPushOptions{}
|
||||
func NewCommonPushOptions(prjClient project.Client) *CommonPushOptions {
|
||||
return &CommonPushOptions{
|
||||
prjClient: prjClient,
|
||||
}
|
||||
}
|
||||
|
||||
//InitEnvInfoFromContext initializes envinfo from the context
|
||||
@@ -60,12 +69,12 @@ func (cpo *CommonPushOptions) ResolveSrcAndConfigFlags() {
|
||||
func (cpo *CommonPushOptions) ResolveProject(prjName string) (err error) {
|
||||
|
||||
// check if project exist
|
||||
isPrjExists, err := project.Exists(cpo.Context.KClient, prjName)
|
||||
isPrjExists, err := cpo.prjClient.Exists(prjName)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to check if project with name %s exists", prjName)
|
||||
}
|
||||
if !isPrjExists {
|
||||
err = project.Create(cpo.Context.KClient, prjName, true)
|
||||
err = cpo.prjClient.Create(prjName, true)
|
||||
if err != nil {
|
||||
return errors.Wrapf(
|
||||
err,
|
||||
|
||||
@@ -6,8 +6,10 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/redhat-developer/odo/pkg/kclient"
|
||||
registryUtil "github.com/redhat-developer/odo/pkg/odo/cli/registry/util"
|
||||
"github.com/redhat-developer/odo/pkg/odo/cmdline"
|
||||
"github.com/redhat-developer/odo/pkg/project"
|
||||
"github.com/zalando/go-keyring"
|
||||
|
||||
"github.com/devfile/library/pkg/devfile"
|
||||
@@ -113,9 +115,9 @@ odo catalog list components
|
||||
%[1]s nodejs --app myapp --project myproject`)
|
||||
|
||||
// NewCreateOptions returns new instance of CreateOptions
|
||||
func NewCreateOptions() *CreateOptions {
|
||||
func NewCreateOptions(prjClient project.Client) *CreateOptions {
|
||||
return &CreateOptions{
|
||||
PushOptions: NewPushOptions(),
|
||||
PushOptions: NewPushOptions(prjClient),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -345,7 +347,9 @@ func (co *CreateOptions) Run() (err error) {
|
||||
|
||||
// NewCmdCreate implements the create odo command
|
||||
func NewCmdCreate(name, fullName string) *cobra.Command {
|
||||
co := NewCreateOptions()
|
||||
// The error is not handled at this point, it will be handled during Context creation
|
||||
kubclient, _ := kclient.New()
|
||||
co := NewCreateOptions(project.NewClient(kubclient))
|
||||
var componentCreateCmd = &cobra.Command{
|
||||
Use: fmt.Sprintf("%s <component_type> [component_name] [flags]", name),
|
||||
Short: "Create a new component",
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"path/filepath"
|
||||
|
||||
"github.com/redhat-developer/odo/pkg/kclient"
|
||||
"github.com/redhat-developer/odo/pkg/project"
|
||||
scontext "github.com/redhat-developer/odo/pkg/segment/context"
|
||||
|
||||
"github.com/redhat-developer/odo/pkg/component"
|
||||
@@ -73,9 +74,9 @@ type PushOptions struct {
|
||||
|
||||
// NewPushOptions returns new instance of PushOptions
|
||||
// with "default" values for certain values, for example, show is "false"
|
||||
func NewPushOptions() *PushOptions {
|
||||
func NewPushOptions(prjClient project.Client) *PushOptions {
|
||||
return &PushOptions{
|
||||
CommonPushOptions: NewCommonPushOptions(),
|
||||
CommonPushOptions: NewCommonPushOptions(prjClient),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,7 +229,9 @@ func (po *PushOptions) Run() (err error) {
|
||||
|
||||
// NewCmdPush implements the push odo command
|
||||
func NewCmdPush(name, fullName string) *cobra.Command {
|
||||
po := NewPushOptions()
|
||||
// The error is not handled at this point, it will be handled during Context creation
|
||||
kubclient, _ := kclient.New()
|
||||
po := NewPushOptions(project.NewClient(kubclient))
|
||||
|
||||
var pushCmd = &cobra.Command{
|
||||
Use: fmt.Sprintf("%s [component name]", name),
|
||||
|
||||
@@ -4,7 +4,9 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/redhat-developer/odo/pkg/kclient"
|
||||
"github.com/redhat-developer/odo/pkg/odo/cmdline"
|
||||
"github.com/redhat-developer/odo/pkg/project"
|
||||
"github.com/redhat-developer/odo/pkg/util"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
@@ -54,8 +56,10 @@ type SetOptions struct {
|
||||
}
|
||||
|
||||
// NewSetOptions creates a new SetOptions instance
|
||||
func NewSetOptions() *SetOptions {
|
||||
return &SetOptions{PushOptions: clicomponent.NewPushOptions()}
|
||||
func NewSetOptions(prjClient project.Client) *SetOptions {
|
||||
return &SetOptions{
|
||||
PushOptions: clicomponent.NewPushOptions(prjClient),
|
||||
}
|
||||
}
|
||||
|
||||
// Complete completes SetOptions after they've been created
|
||||
@@ -174,7 +178,9 @@ func isValidArgumentList(args []string) error {
|
||||
|
||||
// NewCmdSet implements the config set odo command
|
||||
func NewCmdSet(name, fullName string) *cobra.Command {
|
||||
o := NewSetOptions()
|
||||
// The error is not handled at this point, it will be handled during Context creation
|
||||
kubclient, _ := kclient.New()
|
||||
o := NewSetOptions(project.NewClient(kubclient))
|
||||
configurationSetCmd := &cobra.Command{
|
||||
Use: name,
|
||||
Short: "Set a value in odo config file",
|
||||
|
||||
@@ -4,6 +4,8 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/redhat-developer/odo/pkg/kclient"
|
||||
"github.com/redhat-developer/odo/pkg/project"
|
||||
"github.com/redhat-developer/odo/pkg/util"
|
||||
|
||||
"github.com/redhat-developer/odo/pkg/config"
|
||||
@@ -49,8 +51,10 @@ type UnsetOptions struct {
|
||||
}
|
||||
|
||||
// NewUnsetOptions creates a new UnsetOptions instance
|
||||
func NewUnsetOptions() *UnsetOptions {
|
||||
return &UnsetOptions{PushOptions: clicomponent.NewPushOptions()}
|
||||
func NewUnsetOptions(prjClient project.Client) *UnsetOptions {
|
||||
return &UnsetOptions{
|
||||
PushOptions: clicomponent.NewPushOptions(prjClient),
|
||||
}
|
||||
}
|
||||
|
||||
// Complete completes UnsetOptions after they've been created
|
||||
@@ -125,7 +129,9 @@ func (o *UnsetOptions) Run() error {
|
||||
|
||||
// NewCmdUnset implements the config unset odo command
|
||||
func NewCmdUnset(name, fullName string) *cobra.Command {
|
||||
o := NewUnsetOptions()
|
||||
// The error is not handled at this point, it will be handled during Context creation
|
||||
kubclient, _ := kclient.New()
|
||||
o := NewUnsetOptions(project.NewClient(kubclient))
|
||||
configurationUnsetCmd := &cobra.Command{
|
||||
Use: name,
|
||||
Short: "Unset a value in odo config file",
|
||||
|
||||
@@ -3,6 +3,7 @@ package project
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/redhat-developer/odo/pkg/kclient"
|
||||
"github.com/redhat-developer/odo/pkg/log"
|
||||
"github.com/redhat-developer/odo/pkg/machineoutput"
|
||||
"github.com/redhat-developer/odo/pkg/odo/cmdline"
|
||||
@@ -35,6 +36,9 @@ type ProjectCreateOptions struct {
|
||||
// Context
|
||||
*genericclioptions.Context
|
||||
|
||||
// Clients
|
||||
prjClient project.Client
|
||||
|
||||
// Parameters
|
||||
projectName string
|
||||
|
||||
@@ -43,8 +47,10 @@ type ProjectCreateOptions struct {
|
||||
}
|
||||
|
||||
// NewProjectCreateOptions creates a ProjectCreateOptions instance
|
||||
func NewProjectCreateOptions() *ProjectCreateOptions {
|
||||
return &ProjectCreateOptions{}
|
||||
func NewProjectCreateOptions(prjClient project.Client) *ProjectCreateOptions {
|
||||
return &ProjectCreateOptions{
|
||||
prjClient: prjClient,
|
||||
}
|
||||
}
|
||||
|
||||
// Complete completes ProjectCreateOptions after they've been created
|
||||
@@ -77,7 +83,7 @@ func (pco *ProjectCreateOptions) Run() (err error) {
|
||||
}
|
||||
|
||||
// Create the project & end the spinner (if there is any..)
|
||||
err = project.Create(pco.Context.KClient, pco.projectName, pco.waitFlag)
|
||||
err = pco.prjClient.Create(pco.projectName, pco.waitFlag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -87,7 +93,7 @@ func (pco *ProjectCreateOptions) Run() (err error) {
|
||||
log.Successf(successMessage)
|
||||
|
||||
// Set the current project when created
|
||||
err = project.SetCurrent(pco.Context.KClient, pco.projectName)
|
||||
err = pco.prjClient.SetCurrent(pco.projectName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -105,7 +111,9 @@ func (pco *ProjectCreateOptions) Run() (err error) {
|
||||
|
||||
// NewCmdProjectCreate creates the project create command
|
||||
func NewCmdProjectCreate(name, fullName string) *cobra.Command {
|
||||
o := NewProjectCreateOptions()
|
||||
// The error is not handled at this point, it will be handled during Context creation
|
||||
kubclient, _ := kclient.New()
|
||||
o := NewProjectCreateOptions(project.NewClient(kubclient))
|
||||
|
||||
projectCreateCmd := &cobra.Command{
|
||||
Use: name,
|
||||
|
||||
119
pkg/odo/cli/project/create_test.go
Normal file
119
pkg/odo/cli/project/create_test.go
Normal file
@@ -0,0 +1,119 @@
|
||||
package project
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
|
||||
"github.com/redhat-developer/odo/pkg/envinfo"
|
||||
"github.com/redhat-developer/odo/pkg/kclient"
|
||||
"github.com/redhat-developer/odo/pkg/odo/cmdline"
|
||||
"github.com/redhat-developer/odo/pkg/project"
|
||||
"github.com/redhat-developer/odo/pkg/testingutil/filesystem"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func TestCreate(t *testing.T) {
|
||||
|
||||
prefixDir, err := os.MkdirTemp(os.TempDir(), "unittests-")
|
||||
if err != nil {
|
||||
t.Errorf("Error creating temp directory for tests")
|
||||
return
|
||||
}
|
||||
workingDir := filepath.Join(prefixDir, "myapp")
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
populateWorkingDir func(fs filesystem.Filesystem)
|
||||
args []string
|
||||
// existingApps []string
|
||||
wantProjectName string
|
||||
//wantErrValidate string
|
||||
}{
|
||||
{
|
||||
name: "project from args",
|
||||
populateWorkingDir: func(fs filesystem.Filesystem) {
|
||||
_ = fs.MkdirAll(filepath.Join(prefixDir, "myapp", ".odo", "env"), 0755)
|
||||
env, er := envinfo.NewEnvSpecificInfo(filepath.Join(prefixDir, "myapp"))
|
||||
if er != nil {
|
||||
return
|
||||
}
|
||||
_ = env.SetComponentSettings(envinfo.ComponentSettings{
|
||||
Name: "a-name",
|
||||
Project: "a-project",
|
||||
AppName: "an-app-name",
|
||||
})
|
||||
},
|
||||
args: []string{"project-name-to-create"},
|
||||
wantProjectName: "project-name-to-create",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// the first one is to cleanup the directory before execution (in case there are remaining files from a previous execution)
|
||||
os.RemoveAll(prefixDir)
|
||||
// the second one to cleanup after execution
|
||||
defer os.RemoveAll(prefixDir)
|
||||
|
||||
// Fake Cobra
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
cmdline := cmdline.NewMockCmdline(ctrl)
|
||||
cmdline.EXPECT().GetWorkingDirectory().Return(workingDir, nil).AnyTimes()
|
||||
cmdline.EXPECT().FlagValueIfSet("project").Return("").AnyTimes()
|
||||
cmdline.EXPECT().FlagValueIfSet("app").Return("").AnyTimes()
|
||||
cmdline.EXPECT().FlagValueIfSet("component").Return("").AnyTimes()
|
||||
cmdline.EXPECT().FlagValueIfSet("o").Return("").AnyTimes()
|
||||
cmdline.EXPECT().CheckIfConfigurationNeeded().Return(false, nil).AnyTimes()
|
||||
cmdline.EXPECT().Context().Return(context.Background()).AnyTimes()
|
||||
|
||||
// Fake odo Kube client
|
||||
kclient := kclient.NewMockClientInterface(ctrl)
|
||||
cmdline.EXPECT().GetKubeClient().Return(kclient, nil).AnyTimes()
|
||||
|
||||
ns := &corev1.Namespace{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "a-project",
|
||||
},
|
||||
}
|
||||
kclient.EXPECT().GetNamespaceNormal("a-project").Return(ns, nil).AnyTimes()
|
||||
kclient.EXPECT().SetNamespace("a-project").AnyTimes()
|
||||
|
||||
tt.populateWorkingDir(filesystem.DefaultFs{})
|
||||
|
||||
/* Mocks for Complete */
|
||||
prjClient := project.NewMockClient(ctrl)
|
||||
opts := NewProjectCreateOptions(prjClient)
|
||||
|
||||
/* COMPLETE */
|
||||
err = opts.Complete(cmdline, tt.args)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Expected nil error, got %s", err)
|
||||
return
|
||||
}
|
||||
if opts.projectName != tt.wantProjectName {
|
||||
t.Errorf("Got appName %q, expected %q", opts.projectName, tt.wantProjectName)
|
||||
}
|
||||
|
||||
/* VALIDATE */
|
||||
err = opts.Validate()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
/* Mocks for Run */
|
||||
prjClient.EXPECT().Create(tt.wantProjectName, false).Times(1)
|
||||
prjClient.EXPECT().SetCurrent(tt.wantProjectName).Times(1)
|
||||
|
||||
/* RUN */
|
||||
err = opts.Run()
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
odoerrors "github.com/redhat-developer/odo/pkg/errors"
|
||||
"github.com/redhat-developer/odo/pkg/kclient"
|
||||
"github.com/redhat-developer/odo/pkg/log"
|
||||
"github.com/redhat-developer/odo/pkg/machineoutput"
|
||||
"github.com/redhat-developer/odo/pkg/odo/cli/ui"
|
||||
@@ -36,6 +37,9 @@ type ProjectDeleteOptions struct {
|
||||
// Context
|
||||
*genericclioptions.Context
|
||||
|
||||
// Clients
|
||||
prjClient project.Client
|
||||
|
||||
// Parameters
|
||||
projectName string
|
||||
|
||||
@@ -45,8 +49,10 @@ type ProjectDeleteOptions struct {
|
||||
}
|
||||
|
||||
// NewProjectDeleteOptions creates a ProjectDeleteOptions instance
|
||||
func NewProjectDeleteOptions() *ProjectDeleteOptions {
|
||||
return &ProjectDeleteOptions{}
|
||||
func NewProjectDeleteOptions(prjClient project.Client) *ProjectDeleteOptions {
|
||||
return &ProjectDeleteOptions{
|
||||
prjClient: prjClient,
|
||||
}
|
||||
}
|
||||
|
||||
// Complete completes ProjectDeleteOptions after they've been created
|
||||
@@ -59,7 +65,7 @@ func (pdo *ProjectDeleteOptions) Complete(cmdline cmdline.Cmdline, args []string
|
||||
// Validate validates the parameters of the ProjectDeleteOptions
|
||||
func (pdo *ProjectDeleteOptions) Validate() error {
|
||||
// Validate existence of the project to be deleted
|
||||
isValidProject, err := project.Exists(pdo.Context.KClient, pdo.projectName)
|
||||
isValidProject, err := pdo.prjClient.Exists(pdo.projectName)
|
||||
if kerrors.IsForbidden(err) {
|
||||
return &odoerrors.Unauthorized{}
|
||||
}
|
||||
@@ -76,7 +82,7 @@ func (pdo *ProjectDeleteOptions) Run() (err error) {
|
||||
s := &log.Status{}
|
||||
|
||||
// This to set the project in the file and runtime
|
||||
err = project.SetCurrent(pdo.Context.KClient, pdo.projectName)
|
||||
err = pdo.prjClient.SetCurrent(pdo.projectName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -97,7 +103,7 @@ func (pdo *ProjectDeleteOptions) Run() (err error) {
|
||||
defer s.End(false)
|
||||
}
|
||||
|
||||
err := project.Delete(pdo.Context.KClient, pdo.projectName, pdo.waitFlag)
|
||||
err := pdo.prjClient.Delete(pdo.projectName, pdo.waitFlag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -118,7 +124,9 @@ func (pdo *ProjectDeleteOptions) Run() (err error) {
|
||||
|
||||
// NewCmdProjectDelete creates the project delete command
|
||||
func NewCmdProjectDelete(name, fullName string) *cobra.Command {
|
||||
o := NewProjectDeleteOptions()
|
||||
// The error is not handled at this point, it will be handled during Context creation
|
||||
kubclient, _ := kclient.New()
|
||||
o := NewProjectDeleteOptions(project.NewClient(kubclient))
|
||||
|
||||
projectDeleteCmd := &cobra.Command{
|
||||
Use: name,
|
||||
|
||||
155
pkg/odo/cli/project/delete_test.go
Normal file
155
pkg/odo/cli/project/delete_test.go
Normal file
@@ -0,0 +1,155 @@
|
||||
package project
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
|
||||
"github.com/redhat-developer/odo/pkg/envinfo"
|
||||
"github.com/redhat-developer/odo/pkg/kclient"
|
||||
"github.com/redhat-developer/odo/pkg/odo/cmdline"
|
||||
"github.com/redhat-developer/odo/pkg/project"
|
||||
"github.com/redhat-developer/odo/pkg/testingutil/filesystem"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func TestDelete(t *testing.T) {
|
||||
|
||||
prefixDir, err := os.MkdirTemp(os.TempDir(), "unittests-")
|
||||
if err != nil {
|
||||
t.Errorf("Error creating temp directory for tests")
|
||||
return
|
||||
}
|
||||
workingDir := filepath.Join(prefixDir, "myapp")
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
populateWorkingDir func(fs filesystem.Filesystem)
|
||||
args []string
|
||||
projectExists bool
|
||||
wantProjectName string
|
||||
wantErrValidate string
|
||||
}{
|
||||
{
|
||||
name: "project from args",
|
||||
populateWorkingDir: func(fs filesystem.Filesystem) {
|
||||
_ = fs.MkdirAll(filepath.Join(prefixDir, "myapp", ".odo", "env"), 0755)
|
||||
env, er := envinfo.NewEnvSpecificInfo(filepath.Join(prefixDir, "myapp"))
|
||||
if er != nil {
|
||||
return
|
||||
}
|
||||
_ = env.SetComponentSettings(envinfo.ComponentSettings{
|
||||
Name: "a-name",
|
||||
Project: "a-project",
|
||||
AppName: "an-app-name",
|
||||
})
|
||||
},
|
||||
args: []string{"project-name-to-delete"},
|
||||
projectExists: true,
|
||||
wantProjectName: "project-name-to-delete",
|
||||
}, {
|
||||
name: "project from args not existing",
|
||||
populateWorkingDir: func(fs filesystem.Filesystem) {
|
||||
_ = fs.MkdirAll(filepath.Join(prefixDir, "myapp", ".odo", "env"), 0755)
|
||||
env, er := envinfo.NewEnvSpecificInfo(filepath.Join(prefixDir, "myapp"))
|
||||
if er != nil {
|
||||
return
|
||||
}
|
||||
_ = env.SetComponentSettings(envinfo.ComponentSettings{
|
||||
Name: "a-name",
|
||||
Project: "a-project",
|
||||
AppName: "an-app-name",
|
||||
})
|
||||
},
|
||||
args: []string{"project-name-to-delete"},
|
||||
projectExists: false,
|
||||
wantProjectName: "project-name-to-delete",
|
||||
wantErrValidate: `The project "project-name-to-delete" does not exist`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// the first one is to cleanup the directory before execution (in case there are remaining files from a previous execution)
|
||||
os.RemoveAll(prefixDir)
|
||||
// the second one to cleanup after execution
|
||||
defer os.RemoveAll(prefixDir)
|
||||
|
||||
// Fake Cobra
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
cmdline := cmdline.NewMockCmdline(ctrl)
|
||||
cmdline.EXPECT().GetWorkingDirectory().Return(workingDir, nil).AnyTimes()
|
||||
cmdline.EXPECT().FlagValueIfSet("project").Return("").AnyTimes()
|
||||
cmdline.EXPECT().FlagValueIfSet("app").Return("").AnyTimes()
|
||||
cmdline.EXPECT().FlagValueIfSet("component").Return("").AnyTimes()
|
||||
cmdline.EXPECT().FlagValueIfSet("o").Return("").AnyTimes()
|
||||
cmdline.EXPECT().CheckIfConfigurationNeeded().Return(false, nil).AnyTimes()
|
||||
cmdline.EXPECT().Context().Return(context.Background()).AnyTimes()
|
||||
|
||||
// Fake odo Kube client
|
||||
kclient := kclient.NewMockClientInterface(ctrl)
|
||||
cmdline.EXPECT().GetKubeClient().Return(kclient, nil).AnyTimes()
|
||||
|
||||
ns := &corev1.Namespace{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "a-project",
|
||||
},
|
||||
}
|
||||
kclient.EXPECT().GetNamespaceNormal("a-project").Return(ns, nil).AnyTimes()
|
||||
kclient.EXPECT().SetNamespace("a-project").AnyTimes()
|
||||
|
||||
tt.populateWorkingDir(filesystem.DefaultFs{})
|
||||
|
||||
/* Mocks for Complete */
|
||||
prjClient := project.NewMockClient(ctrl)
|
||||
opts := NewProjectDeleteOptions(prjClient)
|
||||
opts.forceFlag = true
|
||||
|
||||
/* COMPLETE */
|
||||
err = opts.Complete(cmdline, tt.args)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Expected nil error, got %s", err)
|
||||
return
|
||||
}
|
||||
if opts.projectName != tt.wantProjectName {
|
||||
t.Errorf("Got appName %q, expected %q", opts.projectName, tt.wantProjectName)
|
||||
}
|
||||
|
||||
/* Mocks for Validate */
|
||||
prjClient.EXPECT().Exists(tt.wantProjectName).Return(tt.projectExists, nil).Times(1)
|
||||
|
||||
/* VALIDATE */
|
||||
err = opts.Validate()
|
||||
|
||||
if err == nil && tt.wantErrValidate != "" {
|
||||
t.Errorf("Expected %v, got no error", tt.wantErrValidate)
|
||||
return
|
||||
}
|
||||
if err != nil && tt.wantErrValidate == "" {
|
||||
t.Errorf("Expected no error, got %v", err.Error())
|
||||
return
|
||||
}
|
||||
if err != nil && tt.wantErrValidate != "" && !strings.Contains(err.Error(), tt.wantErrValidate) {
|
||||
t.Errorf("Expected error %v, got %v", tt.wantErrValidate, err.Error())
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
/* Mocks for Run */
|
||||
prjClient.EXPECT().SetCurrent(tt.wantProjectName).Times(1)
|
||||
prjClient.EXPECT().Delete(tt.wantProjectName, false).Times(1)
|
||||
|
||||
/* RUN */
|
||||
err = opts.Run()
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"os"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/redhat-developer/odo/pkg/kclient"
|
||||
"github.com/redhat-developer/odo/pkg/log"
|
||||
"github.com/redhat-developer/odo/pkg/machineoutput"
|
||||
"github.com/redhat-developer/odo/pkg/odo/cmdline"
|
||||
@@ -30,11 +31,16 @@ var (
|
||||
type ProjectListOptions struct {
|
||||
// Context
|
||||
*genericclioptions.Context
|
||||
|
||||
// Clients
|
||||
prjClient project.Client
|
||||
}
|
||||
|
||||
// NewProjectListOptions creates a new ProjectListOptions instance
|
||||
func NewProjectListOptions() *ProjectListOptions {
|
||||
return &ProjectListOptions{}
|
||||
func NewProjectListOptions(prjClient project.Client) *ProjectListOptions {
|
||||
return &ProjectListOptions{
|
||||
prjClient: prjClient,
|
||||
}
|
||||
}
|
||||
|
||||
// Complete completes ProjectListOptions after they've been created
|
||||
@@ -50,7 +56,7 @@ func (plo *ProjectListOptions) Validate() (err error) {
|
||||
|
||||
// Run contains the logic for the odo project list command
|
||||
func (plo *ProjectListOptions) Run() error {
|
||||
projects, err := project.List(plo.Context.KClient)
|
||||
projects, err := plo.prjClient.List()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -68,7 +74,9 @@ func (plo *ProjectListOptions) Run() error {
|
||||
|
||||
// NewCmdProjectList implements the odo project list command.
|
||||
func NewCmdProjectList(name, fullName string) *cobra.Command {
|
||||
o := NewProjectListOptions()
|
||||
// The error is not handled at this point, it will be handled during Context creation
|
||||
kubclient, _ := kclient.New()
|
||||
o := NewProjectListOptions(project.NewClient(kubclient))
|
||||
projectListCmd := &cobra.Command{
|
||||
Use: name,
|
||||
Short: listLongDesc,
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
odoerrors "github.com/redhat-developer/odo/pkg/errors"
|
||||
"github.com/redhat-developer/odo/pkg/kclient"
|
||||
"github.com/redhat-developer/odo/pkg/log"
|
||||
"github.com/redhat-developer/odo/pkg/odo/cmdline"
|
||||
"github.com/redhat-developer/odo/pkg/odo/genericclioptions"
|
||||
@@ -36,6 +37,9 @@ type ProjectSetOptions struct {
|
||||
// Context
|
||||
*genericclioptions.Context
|
||||
|
||||
// Clients
|
||||
prjClient project.Client
|
||||
|
||||
// Parameters
|
||||
projectName string
|
||||
|
||||
@@ -44,8 +48,10 @@ type ProjectSetOptions struct {
|
||||
}
|
||||
|
||||
// NewProjectSetOptions creates a ProjectSetOptions instance
|
||||
func NewProjectSetOptions() *ProjectSetOptions {
|
||||
return &ProjectSetOptions{}
|
||||
func NewProjectSetOptions(prjClient project.Client) *ProjectSetOptions {
|
||||
return &ProjectSetOptions{
|
||||
prjClient: prjClient,
|
||||
}
|
||||
}
|
||||
|
||||
// Complete completes ProjectSetOptions after they've been created
|
||||
@@ -64,7 +70,7 @@ func (pso *ProjectSetOptions) Complete(cmdline cmdline.Cmdline, args []string) (
|
||||
// Validate validates the parameters of the ProjectSetOptions
|
||||
func (pso *ProjectSetOptions) Validate() (err error) {
|
||||
|
||||
exists, err := project.Exists(pso.Context.KClient, pso.projectName)
|
||||
exists, err := pso.prjClient.Exists(pso.projectName)
|
||||
if kerrors.IsForbidden(err) {
|
||||
return &odoerrors.Unauthorized{}
|
||||
}
|
||||
@@ -78,7 +84,7 @@ func (pso *ProjectSetOptions) Validate() (err error) {
|
||||
// Run runs the project set command
|
||||
func (pso *ProjectSetOptions) Run() (err error) {
|
||||
current := pso.GetProject()
|
||||
err = project.SetCurrent(pso.Context.KClient, pso.projectName)
|
||||
err = pso.prjClient.SetCurrent(pso.projectName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -96,7 +102,9 @@ func (pso *ProjectSetOptions) Run() (err error) {
|
||||
|
||||
// NewCmdProjectSet creates the project set command
|
||||
func NewCmdProjectSet(name, fullName string) *cobra.Command {
|
||||
o := NewProjectSetOptions()
|
||||
// The error is not handled at this point, it will be handled during Context creation
|
||||
kubclient, _ := kclient.New()
|
||||
o := NewProjectSetOptions(project.NewClient(kubclient))
|
||||
|
||||
projectSetCmd := &cobra.Command{
|
||||
Use: name,
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
|
||||
devfilev1 "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/redhat-developer/odo/pkg/kclient"
|
||||
"github.com/redhat-developer/odo/pkg/localConfigProvider"
|
||||
"github.com/redhat-developer/odo/pkg/log"
|
||||
"github.com/redhat-developer/odo/pkg/machineoutput"
|
||||
@@ -14,6 +15,7 @@ import (
|
||||
"github.com/redhat-developer/odo/pkg/odo/genericclioptions"
|
||||
odoutil "github.com/redhat-developer/odo/pkg/odo/util"
|
||||
"github.com/redhat-developer/odo/pkg/odo/util/completion"
|
||||
"github.com/redhat-developer/odo/pkg/project"
|
||||
"github.com/redhat-developer/odo/pkg/url"
|
||||
|
||||
"github.com/redhat-developer/odo/pkg/util"
|
||||
@@ -75,8 +77,8 @@ type CreateOptions struct {
|
||||
}
|
||||
|
||||
// NewURLCreateOptions creates a new CreateOptions instance
|
||||
func NewURLCreateOptions() *CreateOptions {
|
||||
return &CreateOptions{PushOptions: clicomponent.NewPushOptions()}
|
||||
func NewURLCreateOptions(prjClient project.Client) *CreateOptions {
|
||||
return &CreateOptions{PushOptions: clicomponent.NewPushOptions(prjClient)}
|
||||
}
|
||||
|
||||
// Complete completes CreateOptions after they've been Created
|
||||
@@ -193,7 +195,9 @@ func (o *CreateOptions) Run() (err error) {
|
||||
|
||||
// NewCmdURLCreate implements the odo url create command.
|
||||
func NewCmdURLCreate(name, fullName string) *cobra.Command {
|
||||
o := NewURLCreateOptions()
|
||||
// The error is not handled at this point, it will be handled during Context creation
|
||||
kubclient, _ := kclient.New()
|
||||
o := NewURLCreateOptions(project.NewClient(kubclient))
|
||||
urlCreateCmd := &cobra.Command{
|
||||
Use: name + " [url name]",
|
||||
Short: urlCreateShortDesc,
|
||||
|
||||
@@ -3,6 +3,7 @@ package url
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/redhat-developer/odo/pkg/kclient"
|
||||
"github.com/redhat-developer/odo/pkg/log"
|
||||
clicomponent "github.com/redhat-developer/odo/pkg/odo/cli/component"
|
||||
"github.com/redhat-developer/odo/pkg/odo/cli/ui"
|
||||
@@ -10,6 +11,7 @@ import (
|
||||
"github.com/redhat-developer/odo/pkg/odo/genericclioptions"
|
||||
odoutil "github.com/redhat-developer/odo/pkg/odo/util"
|
||||
"github.com/redhat-developer/odo/pkg/odo/util/completion"
|
||||
"github.com/redhat-developer/odo/pkg/project"
|
||||
"github.com/spf13/cobra"
|
||||
ktemplates "k8s.io/kubectl/pkg/util/templates"
|
||||
)
|
||||
@@ -38,8 +40,8 @@ type DeleteOptions struct {
|
||||
}
|
||||
|
||||
// NewURLDeleteOptions creates a new DeleteOptions instance
|
||||
func NewURLDeleteOptions() *DeleteOptions {
|
||||
return &DeleteOptions{PushOptions: clicomponent.NewPushOptions()}
|
||||
func NewURLDeleteOptions(prjClient project.Client) *DeleteOptions {
|
||||
return &DeleteOptions{PushOptions: clicomponent.NewPushOptions(prjClient)}
|
||||
}
|
||||
|
||||
// Complete completes DeleteOptions after they've been Deleted
|
||||
@@ -104,7 +106,9 @@ func (o *DeleteOptions) Run() (err error) {
|
||||
|
||||
// NewCmdURLDelete implements the odo url delete command.
|
||||
func NewCmdURLDelete(name, fullName string) *cobra.Command {
|
||||
o := NewURLDeleteOptions()
|
||||
// The error is not handled at this point, it will be handled during Context creation
|
||||
kubclient, _ := kclient.New()
|
||||
o := NewURLDeleteOptions(project.NewClient(kubclient))
|
||||
urlDeleteCmd := &cobra.Command{
|
||||
Use: name + " [url name]",
|
||||
Short: urlDeleteShortDesc,
|
||||
|
||||
@@ -42,7 +42,7 @@ type internalCxt struct {
|
||||
component string
|
||||
// componentContext is the value passed with the `--context` flag
|
||||
componentContext string
|
||||
// outputFlag is the value passed with the `--output` flag
|
||||
// outputFlag is the value passed with the `-o` flag
|
||||
outputFlag string
|
||||
// The path of the detected devfile
|
||||
devfilePath string
|
||||
@@ -202,6 +202,10 @@ func (o *Context) GetOutputFlag() string {
|
||||
return o.outputFlag
|
||||
}
|
||||
|
||||
func (o *Context) IsJSON() bool {
|
||||
return o.outputFlag == "json"
|
||||
}
|
||||
|
||||
func (o *Context) GetComponentContext() string {
|
||||
return o.componentContext
|
||||
}
|
||||
|
||||
@@ -342,7 +342,7 @@ func TestNew(t *testing.T) {
|
||||
cmdline.EXPECT().FlagValueIfSet("project").Return(tt.input.projectFlag).AnyTimes()
|
||||
cmdline.EXPECT().FlagValueIfSet("app").Return(tt.input.appFlag).AnyTimes()
|
||||
cmdline.EXPECT().FlagValueIfSet("component").Return(tt.input.componentFlag).AnyTimes()
|
||||
cmdline.EXPECT().FlagValueIfSet("output").Return(tt.input.outputFlag).AnyTimes()
|
||||
cmdline.EXPECT().FlagValueIfSet("o").Return(tt.input.outputFlag).AnyTimes()
|
||||
cmdline.EXPECT().IsFlagSet("all").Return(tt.input.allFlagSet).AnyTimes()
|
||||
cmdline.EXPECT().GetParentName().Return(tt.input.parentCommandName).AnyTimes()
|
||||
cmdline.EXPECT().GetName().Return(tt.input.commandName).AnyTimes()
|
||||
|
||||
@@ -17,7 +17,8 @@ import (
|
||||
var AppCompletionHandler = func(cmd *cobra.Command, args parsedArgs, context *genericclioptions.Context) (completions []string) {
|
||||
completions = make([]string, 0)
|
||||
|
||||
applications, err := application.List(context.KClient)
|
||||
appClient := application.NewClient(context.KClient)
|
||||
applications, err := appClient.List()
|
||||
if err != nil {
|
||||
return completions
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ const (
|
||||
// ComponentFlagName is the name of the flag allowing a user to specify which component to operate on
|
||||
ComponentFlagName = "component"
|
||||
// OutputFlagName is the name of the flag allowing user to specify output format
|
||||
OutputFlagName = "output"
|
||||
OutputFlagName = "o"
|
||||
// ContextFlagName is the name of the flag allowing a user to specify the location of the component settings
|
||||
ContextFlagName = "context"
|
||||
)
|
||||
|
||||
133
pkg/project/kubernetes.go
Normal file
133
pkg/project/kubernetes.go
Normal file
@@ -0,0 +1,133 @@
|
||||
package project
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/redhat-developer/odo/pkg/kclient"
|
||||
)
|
||||
|
||||
type kubernetesClient struct {
|
||||
client kclient.ClientInterface
|
||||
}
|
||||
|
||||
func NewClient(client kclient.ClientInterface) Client {
|
||||
return kubernetesClient{
|
||||
client: client,
|
||||
}
|
||||
}
|
||||
|
||||
// SetCurrent sets projectName as the current project
|
||||
func (o kubernetesClient) SetCurrent(projectName string) error {
|
||||
err := o.client.SetCurrentNamespace(projectName)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to set current project to"+projectName)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Create a new project, either by creating a `project.openshift.io` resource if supported by the cluster
|
||||
// (which will trigger the creation of a namespace),
|
||||
// or by creating directly a `namespace` resource.
|
||||
// With the `wait` flag, the function will wait for the `default` service account
|
||||
// to be created in the namespace before returning
|
||||
func (o kubernetesClient) Create(projectName string, wait bool) error {
|
||||
if projectName == "" {
|
||||
return errors.Errorf("no project name given")
|
||||
}
|
||||
|
||||
projectSupport, err := o.client.IsProjectSupported()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to detect project support")
|
||||
}
|
||||
|
||||
if projectSupport {
|
||||
err = o.client.CreateNewProject(projectName, wait)
|
||||
|
||||
} else {
|
||||
_, err = o.client.CreateNamespace(projectName)
|
||||
}
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to create new project")
|
||||
}
|
||||
|
||||
if wait {
|
||||
err = o.client.WaitForServiceAccountInNamespace(projectName, "default")
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to wait for service account")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Delete deletes the project (the `project` resource if supported, or directly the `namespace`)
|
||||
// with the name projectName and returns an error if any
|
||||
func (o kubernetesClient) Delete(projectName string, wait bool) error {
|
||||
if projectName == "" {
|
||||
return errors.Errorf("no project name given")
|
||||
}
|
||||
|
||||
projectSupport, err := o.client.IsProjectSupported()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to detect project support")
|
||||
}
|
||||
|
||||
if projectSupport {
|
||||
err = o.client.DeleteProject(projectName, wait)
|
||||
} else {
|
||||
err = o.client.DeleteNamespace(projectName, wait)
|
||||
}
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "unable to delete project %q", projectName)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// List all the projects on the cluster and returns an error if any
|
||||
func (o kubernetesClient) List() (ProjectList, error) {
|
||||
currentProject := o.client.GetCurrentNamespace()
|
||||
|
||||
projectSupport, err := o.client.IsProjectSupported()
|
||||
if err != nil {
|
||||
return ProjectList{}, errors.Wrap(err, "unable to detect project support")
|
||||
}
|
||||
|
||||
var allProjects []string
|
||||
if projectSupport {
|
||||
allProjects, err = o.client.ListProjectNames()
|
||||
} else {
|
||||
allProjects, err = o.client.GetNamespaces()
|
||||
}
|
||||
if err != nil {
|
||||
return ProjectList{}, errors.Wrap(err, "cannot get all the projects")
|
||||
}
|
||||
|
||||
projects := make([]Project, len(allProjects))
|
||||
for i, project := range allProjects {
|
||||
isActive := project == currentProject
|
||||
projects[i] = NewProject(project, isActive)
|
||||
}
|
||||
|
||||
return NewProjectList(projects), nil
|
||||
}
|
||||
|
||||
// Exists checks whether a project with the name `projectName` exists and returns an error if any
|
||||
func (o kubernetesClient) Exists(projectName string) (bool, error) {
|
||||
projectSupport, err := o.client.IsProjectSupported()
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "unable to detect project support")
|
||||
}
|
||||
|
||||
if projectSupport {
|
||||
project, err := o.client.GetProject(projectName)
|
||||
if err != nil || project == nil {
|
||||
return false, err
|
||||
}
|
||||
} else {
|
||||
namespace, err := o.client.GetNamespace(projectName)
|
||||
if err != nil || namespace == nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
@@ -62,6 +62,7 @@ func TestCreate(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
kc := kclient.NewMockClientInterface(ctrl)
|
||||
appClient := NewClient(kc)
|
||||
|
||||
if tt.expectedErr == false {
|
||||
kc.EXPECT().IsProjectSupported().Return(tt.isProjectSupported, tt.isProjectSupportedErr)
|
||||
@@ -75,7 +76,7 @@ func TestCreate(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
err := Create(kc, tt.projectName, tt.wait)
|
||||
err := appClient.Create(tt.projectName, tt.wait)
|
||||
|
||||
if err != nil != tt.expectedErr {
|
||||
t.Errorf("expected error %v, got %v", tt.expectedErr, err)
|
||||
@@ -136,6 +137,7 @@ func TestDelete(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
kc := kclient.NewMockClientInterface(ctrl)
|
||||
appClient := NewClient(kc)
|
||||
|
||||
if tt.expectedErr == false {
|
||||
kc.EXPECT().IsProjectSupported().Return(tt.isProjectSupported, tt.isProjectSupportedErr)
|
||||
@@ -146,7 +148,7 @@ func TestDelete(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
err := Delete(kc, tt.projectName, tt.wait)
|
||||
err := appClient.Delete(tt.projectName, tt.wait)
|
||||
|
||||
if err != nil != tt.expectedErr {
|
||||
t.Errorf("expected error %v, got %v", tt.expectedErr, err)
|
||||
@@ -214,6 +216,7 @@ func TestList(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
kc := kclient.NewMockClientInterface(ctrl)
|
||||
appClient := NewClient(kc)
|
||||
|
||||
kc.EXPECT().GetCurrentNamespace().Times(1)
|
||||
|
||||
@@ -226,7 +229,7 @@ func TestList(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
list, err := List(kc)
|
||||
list, err := appClient.List()
|
||||
|
||||
if err != nil != tt.expectedErr {
|
||||
t.Errorf("expected error %v, got %v", tt.expectedErr, err)
|
||||
@@ -269,6 +272,7 @@ func TestExists(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
kc := kclient.NewMockClientInterface(ctrl)
|
||||
appClient := NewClient(kc)
|
||||
|
||||
if tt.expectedErr == false {
|
||||
kc.EXPECT().IsProjectSupported().Return(tt.isProjectSupported, tt.isProjectSupportedErr)
|
||||
@@ -279,7 +283,7 @@ func TestExists(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
_, err := Exists(kc, tt.projectName)
|
||||
_, err := appClient.Exists(tt.projectName)
|
||||
|
||||
if err != nil != tt.expectedErr {
|
||||
t.Errorf("expected error %v, got %v", tt.expectedErr, err)
|
||||
106
pkg/project/mock.go
Normal file
106
pkg/project/mock.go
Normal file
@@ -0,0 +1,106 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: pkg/project/project.go
|
||||
|
||||
// Package project is a generated GoMock package.
|
||||
package project
|
||||
|
||||
import (
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
// MockClient is a mock of Client interface.
|
||||
type MockClient struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockClientMockRecorder
|
||||
}
|
||||
|
||||
// MockClientMockRecorder is the mock recorder for MockClient.
|
||||
type MockClientMockRecorder struct {
|
||||
mock *MockClient
|
||||
}
|
||||
|
||||
// NewMockClient creates a new mock instance.
|
||||
func NewMockClient(ctrl *gomock.Controller) *MockClient {
|
||||
mock := &MockClient{ctrl: ctrl}
|
||||
mock.recorder = &MockClientMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockClient) EXPECT() *MockClientMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// Create mocks base method.
|
||||
func (m *MockClient) Create(projectName string, wait bool) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Create", projectName, wait)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Create indicates an expected call of Create.
|
||||
func (mr *MockClientMockRecorder) Create(projectName, wait interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockClient)(nil).Create), projectName, wait)
|
||||
}
|
||||
|
||||
// Delete mocks base method.
|
||||
func (m *MockClient) Delete(projectName string, wait bool) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Delete", projectName, wait)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Delete indicates an expected call of Delete.
|
||||
func (mr *MockClientMockRecorder) Delete(projectName, wait interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockClient)(nil).Delete), projectName, wait)
|
||||
}
|
||||
|
||||
// Exists mocks base method.
|
||||
func (m *MockClient) Exists(projectName string) (bool, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Exists", projectName)
|
||||
ret0, _ := ret[0].(bool)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// Exists indicates an expected call of Exists.
|
||||
func (mr *MockClientMockRecorder) Exists(projectName interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Exists", reflect.TypeOf((*MockClient)(nil).Exists), projectName)
|
||||
}
|
||||
|
||||
// List mocks base method.
|
||||
func (m *MockClient) List() (ProjectList, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "List")
|
||||
ret0, _ := ret[0].(ProjectList)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// List indicates an expected call of List.
|
||||
func (mr *MockClientMockRecorder) List() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "List", reflect.TypeOf((*MockClient)(nil).List))
|
||||
}
|
||||
|
||||
// SetCurrent mocks base method.
|
||||
func (m *MockClient) SetCurrent(projectName string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SetCurrent", projectName)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// SetCurrent indicates an expected call of SetCurrent.
|
||||
func (mr *MockClientMockRecorder) SetCurrent(projectName interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetCurrent", reflect.TypeOf((*MockClient)(nil).SetCurrent), projectName)
|
||||
}
|
||||
@@ -1,131 +1,9 @@
|
||||
package project
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/redhat-developer/odo/pkg/kclient"
|
||||
)
|
||||
|
||||
// SetCurrent sets projectName as the current project
|
||||
func SetCurrent(client kclient.ClientInterface, projectName string) error {
|
||||
err := client.SetCurrentNamespace(projectName)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to set current project to"+projectName)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Create a new project, either by creating a `project.openshift.io` resource if supported by the cluster
|
||||
// (which will trigger the creation of a namespace),
|
||||
// or by creating directly a `namespace` resource.
|
||||
// With the `wait` flag, the function will wait for the `default` service account
|
||||
// to be created in the namespace before to return.
|
||||
func Create(client kclient.ClientInterface, projectName string, wait bool) error {
|
||||
if projectName == "" {
|
||||
return errors.Errorf("no project name given")
|
||||
}
|
||||
|
||||
projectSupport, err := client.IsProjectSupported()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to detect project support")
|
||||
}
|
||||
if projectSupport {
|
||||
err = client.CreateNewProject(projectName, wait)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to create new project")
|
||||
}
|
||||
|
||||
} else {
|
||||
_, err = client.CreateNamespace(projectName)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to create new project")
|
||||
}
|
||||
}
|
||||
|
||||
if wait {
|
||||
err = client.WaitForServiceAccountInNamespace(projectName, "default")
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to wait for service account")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Delete deletes the project (the `project` resource if supported, or directly the `namespace`)
|
||||
// with the name projectName and returns an error if any
|
||||
func Delete(client kclient.ClientInterface, projectName string, wait bool) error {
|
||||
if projectName == "" {
|
||||
return errors.Errorf("no project name given")
|
||||
}
|
||||
|
||||
projectSupport, err := client.IsProjectSupported()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to detect project support")
|
||||
}
|
||||
|
||||
if projectSupport {
|
||||
// Delete the requested project
|
||||
err := client.DeleteProject(projectName, wait)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "unable to delete project %s", projectName)
|
||||
}
|
||||
} else {
|
||||
err := client.DeleteNamespace(projectName, wait)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "unable to delete namespace %s", projectName)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// List all the projects on the cluster and returns an error if any
|
||||
func List(client kclient.ClientInterface) (ProjectList, error) {
|
||||
currentProject := client.GetCurrentNamespace()
|
||||
|
||||
projectSupport, err := client.IsProjectSupported()
|
||||
if err != nil {
|
||||
return ProjectList{}, errors.Wrap(err, "unable to detect project support")
|
||||
}
|
||||
|
||||
var allProjects []string
|
||||
if projectSupport {
|
||||
allProjects, err = client.ListProjectNames()
|
||||
if err != nil {
|
||||
return ProjectList{}, errors.Wrap(err, "cannot get all the projects")
|
||||
}
|
||||
} else {
|
||||
allProjects, err = client.GetNamespaces()
|
||||
if err != nil {
|
||||
return ProjectList{}, errors.Wrap(err, "cannot get all the namespaces")
|
||||
}
|
||||
}
|
||||
|
||||
projects := make([]Project, len(allProjects))
|
||||
for i, project := range allProjects {
|
||||
isActive := project == currentProject
|
||||
projects[i] = NewProject(project, isActive)
|
||||
}
|
||||
|
||||
return NewProjectList(projects), nil
|
||||
}
|
||||
|
||||
// Exists checks whether a project with the name `projectName` exists and returns an error if any
|
||||
func Exists(client kclient.ClientInterface, projectName string) (bool, error) {
|
||||
projectSupport, err := client.IsProjectSupported()
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "unable to detect project support")
|
||||
}
|
||||
|
||||
if projectSupport {
|
||||
project, err := client.GetProject(projectName)
|
||||
if err != nil || project == nil {
|
||||
return false, err
|
||||
}
|
||||
} else {
|
||||
namespace, err := client.GetNamespace(projectName)
|
||||
if err != nil || namespace == nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
return true, nil
|
||||
type Client interface {
|
||||
SetCurrent(projectName string) error
|
||||
Create(projectName string, wait bool) error
|
||||
Delete(projectName string, wait bool) error
|
||||
List() (ProjectList, error)
|
||||
Exists(projectName string) (bool, error)
|
||||
}
|
||||
|
||||
@@ -91,7 +91,13 @@ type DownloadParams struct {
|
||||
func ConvertLabelsToSelector(labels map[string]string) string {
|
||||
var selector string
|
||||
isFirst := true
|
||||
for k, v := range labels {
|
||||
keys := make([]string, 0, len(labels))
|
||||
for k := range labels {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
for _, k := range keys {
|
||||
v := labels[k]
|
||||
if isFirst {
|
||||
isFirst = false
|
||||
if v == "" {
|
||||
@@ -694,6 +700,7 @@ func RemoveDuplicates(s []string) []string {
|
||||
for item := range m {
|
||||
result = append(result, item)
|
||||
}
|
||||
sort.Strings(result)
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ import (
|
||||
"reflect"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -1057,7 +1056,7 @@ func TestRemoveDuplicate(t *testing.T) {
|
||||
name: "Case 2 - Remove duplicates, none in array",
|
||||
args: args{
|
||||
input: []string{"bar", "foo"},
|
||||
output: []string{"foo", "bar"},
|
||||
output: []string{"bar", "foo"},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -1067,10 +1066,6 @@ func TestRemoveDuplicate(t *testing.T) {
|
||||
// Run function RemoveDuplicate
|
||||
output := RemoveDuplicates(tt.args.input)
|
||||
|
||||
// sort the strings
|
||||
sort.Strings(output)
|
||||
sort.Strings(tt.args.output)
|
||||
|
||||
if !(reflect.DeepEqual(output, tt.args.output)) {
|
||||
t.Errorf("expected %v, got %v", tt.args.output, output)
|
||||
}
|
||||
@@ -2686,7 +2681,7 @@ func TestGetGitOriginPath(t *testing.T) {
|
||||
func TestConvertLabelsToSelector(t *testing.T) {
|
||||
cases := []struct {
|
||||
labels map[string]string
|
||||
want []string
|
||||
want string
|
||||
}{
|
||||
{
|
||||
labels: map[string]string{
|
||||
@@ -2694,7 +2689,7 @@ func TestConvertLabelsToSelector(t *testing.T) {
|
||||
"app.kubernetes.io/managed-by": "odo",
|
||||
"app.kubernetes.io/managed-by-version": "v2.1",
|
||||
},
|
||||
want: []string{"app=app", "app.kubernetes.io/managed-by=odo", "app.kubernetes.io/managed-by-version=v2.1"},
|
||||
want: "app=app,app.kubernetes.io/managed-by=odo,app.kubernetes.io/managed-by-version=v2.1",
|
||||
},
|
||||
{
|
||||
labels: map[string]string{
|
||||
@@ -2702,28 +2697,26 @@ func TestConvertLabelsToSelector(t *testing.T) {
|
||||
"app.kubernetes.io/managed-by": "!odo",
|
||||
"app.kubernetes.io/managed-by-version": "4.8",
|
||||
},
|
||||
want: []string{"app=app", "app.kubernetes.io/managed-by!=odo", "app.kubernetes.io/managed-by-version=4.8"},
|
||||
want: "app=app,app.kubernetes.io/managed-by!=odo,app.kubernetes.io/managed-by-version=4.8",
|
||||
},
|
||||
{
|
||||
labels: map[string]string{
|
||||
"app.kubernetes.io/managed-by": "odo",
|
||||
},
|
||||
want: []string{"app.kubernetes.io/managed-by=odo"},
|
||||
want: "app.kubernetes.io/managed-by=odo",
|
||||
},
|
||||
{
|
||||
labels: map[string]string{
|
||||
"app.kubernetes.io/managed-by": "!odo",
|
||||
},
|
||||
want: []string{"app.kubernetes.io/managed-by!=odo"},
|
||||
want: "app.kubernetes.io/managed-by!=odo",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range cases {
|
||||
got := ConvertLabelsToSelector(tt.labels)
|
||||
for _, want := range tt.want {
|
||||
if !strings.Contains(got, want) {
|
||||
t.Errorf("got: %q\nwant:%q", got, tt.want)
|
||||
}
|
||||
if got != tt.want {
|
||||
t.Errorf("got: %q\nwant:%q", got, tt.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,3 +26,11 @@ mockgen -source=pkg/devfile/image/image.go \
|
||||
mockgen -source=pkg/odo/cmdline/cmdline.go \
|
||||
-package cmdline \
|
||||
-destination pkg/odo/cmdline/mock.go
|
||||
|
||||
mockgen -source=pkg/application/application.go \
|
||||
-package application \
|
||||
-destination pkg/application/mock.go
|
||||
|
||||
mockgen -source=pkg/project/project.go \
|
||||
-package project \
|
||||
-destination pkg/project/mock.go
|
||||
|
||||
Reference in New Issue
Block a user