mirror of
https://github.com/redhat-developer/odo.git
synced 2025-10-19 03:06:19 +03:00
Create cleanup (#5589)
* Cleanup create code * Add missing integration tests from odo create to odo init * Add CreateLocalEnv to create .odo/env/env.yaml file for commands that require it but cannot create it * Remove 'odo create' usages from integration tests * Remove create reference from the Makefile * REmove create doc from v3 Signed-off-by: Parthvi Vala <pvala@redhat.com> * Remove test files * Fix CI failure Signed-off-by: Parthvi Vala <pvala@redhat.com>
This commit is contained in:
6
Makefile
6
Makefile
@@ -187,9 +187,9 @@ test-plugin-handler: install ## Run odo plugin handler tests
|
||||
test-cmd-devfile-list: install ## Run odo list devfile command tests
|
||||
$(RUN_GINKGO) $(GINKGO_FLAGS) -focus="odo list with devfile" tests/integration/devfile/
|
||||
|
||||
.PHONY: test-cmd-devfile-create
|
||||
test-cmd-devfile-create: install ## Run odo create devfile command tests
|
||||
$(RUN_GINKGO) $(GINKGO_FLAGS) -focus="odo devfile create command tests" tests/integration/devfile/
|
||||
.PHONY: test-cmd-devfile-init
|
||||
test-cmd-devfile-init: install ## Run odo init devfile command tests
|
||||
$(RUN_GINKGO) $(GINKGO_FLAGS) -focus="odo devfile init command tests" tests/integration/devfile/
|
||||
|
||||
.PHONY: test-cmd-devfile-push
|
||||
test-cmd-devfile-push: install ## Run odo push devfile command tests
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
---
|
||||
title: odo create
|
||||
sidebar_position: 3
|
||||
---
|
||||
|
||||
odo uses the [_devfile_](https://devfile.io) to store the configuration of and describe the resources like storage, services, etc. of a component. The _odo create_ command allows you to generate this file.
|
||||
|
||||
## Creating a component
|
||||
|
||||
To create a _devfile_ for an existing project, you can execute `odo create` with the name and type of your component (for example, nodejs or go):
|
||||
|
||||
```
|
||||
odo create nodejs mynodejs
|
||||
```
|
||||
|
||||
Here `nodejs` is the type of the component and `mynodejs` is the name of the component odo creates for you.
|
||||
|
||||
> Note: for a list of all the supported component types, run `odo catalog list components`.
|
||||
|
||||
If your source code exists outside the current directory, the `--context` flag can be used to specify the path. For example, if the source for the nodejs component was in a folder called `node-backend` relative to the current working directory, you could run:
|
||||
|
||||
```
|
||||
odo create nodejs mynodejs --context ./node-backend
|
||||
```
|
||||
|
||||
Both relative and absolute paths are supported.
|
||||
|
||||
To specify the project or app of where your component will be deployed, you can use the `--project` and `--app` flags.
|
||||
|
||||
For example, to create a component that is a part of the `myapp` app inside the `backend` project:
|
||||
|
||||
```
|
||||
odo create nodejs --app myapp --project backend
|
||||
```
|
||||
|
||||
> Note: if these are not specified, they will default to the active app and project
|
||||
|
||||
## Starter projects
|
||||
|
||||
If you do not have existing source code but wish to get up and running quickly to experiment with devfiles and components, you could use the starter projects to get started. To use a starter project, include the `--starter` flag in your `odo create` command.
|
||||
|
||||
To get a list of available starter projects for a component type, you can use the `odo catalog describe component` command. For example, to get all available starter projects for the nodejs component type, run:
|
||||
|
||||
```
|
||||
odo catalog describe component nodejs
|
||||
```
|
||||
|
||||
Then specify the desired project with the `--starter` flag:
|
||||
|
||||
```
|
||||
odo create nodejs --starter nodejs-starter
|
||||
```
|
||||
|
||||
This will download the example template corresponding to the chosen component type (in the example above, `nodejs`) in your current directory (or the path provided with the `--context` flag).
|
||||
|
||||
If a starter project has its own devfile, then this devfile will be preserved.
|
||||
|
||||
## Using an existing devfile
|
||||
|
||||
If you want to create a new component from an existing devfile, you can do so by specifying the path to the devfile with the `--devfile` flag.
|
||||
|
||||
For example, the following command will create a component called `mynodejs`, based on the devfile from GitHub:
|
||||
|
||||
```
|
||||
odo create mynodejs --devfile https://raw.githubusercontent.com/odo-devfiles/registry/master/devfiles/nodejs/devfile.yaml
|
||||
```
|
||||
|
||||
## Interactive creation
|
||||
|
||||
The `odo create` command can also be run interactively. Execute `odo create`, which will guide you through a list of steps to create a component:
|
||||
|
||||
```sh
|
||||
odo create
|
||||
|
||||
? Which devfile component type do you wish to create go
|
||||
? What do you wish to name the new devfile component go-api
|
||||
? What project do you want the devfile component to be created in default
|
||||
Devfile Object Validation
|
||||
✓ Checking devfile existence [164258ns]
|
||||
✓ Creating a devfile component from registry: DefaultDevfileRegistry [246051ns]
|
||||
Validation
|
||||
✓ Validating if devfile name is correct [92255ns]
|
||||
? Do you want to download a starter project Yes
|
||||
|
||||
Starter Project
|
||||
✓ Downloading starter project go-starter from https://github.com/devfile-samples/devfile-stack-go.git [429ms]
|
||||
|
||||
Please use `odo push` command to create the component with source deployed
|
||||
```
|
||||
|
||||
You will be prompted to choose the component type, name and the project for the component. You can also choose whether or not to download a starter project. Once finished, a new `devfile.yaml` file should be created in the working directory.
|
||||
To deploy these resources to your cluster, run `odo push`.
|
||||
@@ -13,85 +13,25 @@ import (
|
||||
"github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
|
||||
"github.com/devfile/api/v2/pkg/devfile"
|
||||
"github.com/devfile/library/pkg/devfile/parser"
|
||||
parsercommon "github.com/devfile/library/pkg/devfile/parser/data/v2/common"
|
||||
dfutil "github.com/devfile/library/pkg/util"
|
||||
|
||||
"github.com/redhat-developer/odo/pkg/devfile/location"
|
||||
|
||||
servicebinding "github.com/redhat-developer/service-binding-operator/apis/binding/v1alpha1"
|
||||
|
||||
applabels "github.com/redhat-developer/odo/pkg/application/labels"
|
||||
componentlabels "github.com/redhat-developer/odo/pkg/component/labels"
|
||||
"github.com/redhat-developer/odo/pkg/envinfo"
|
||||
"github.com/redhat-developer/odo/pkg/kclient"
|
||||
"github.com/redhat-developer/odo/pkg/localConfigProvider"
|
||||
"github.com/redhat-developer/odo/pkg/preference"
|
||||
"github.com/redhat-developer/odo/pkg/service"
|
||||
urlpkg "github.com/redhat-developer/odo/pkg/url"
|
||||
"github.com/redhat-developer/odo/pkg/util"
|
||||
|
||||
servicebinding "github.com/redhat-developer/service-binding-operator/apis/binding/v1alpha1"
|
||||
|
||||
v1 "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/klog"
|
||||
)
|
||||
|
||||
const componentRandomNamePartsMaxLen = 12
|
||||
const componentNameMaxRetries = 3
|
||||
const componentNameMaxLen = -1
|
||||
const NotAvailable = "Not available"
|
||||
const apiVersion = "odo.dev/v1alpha1"
|
||||
|
||||
// GetComponentDir returns source repo name
|
||||
// Parameters:
|
||||
// path: source path
|
||||
// Returns: directory name
|
||||
func GetComponentDir(path string) (string, error) {
|
||||
retVal := ""
|
||||
if path != "" {
|
||||
retVal = filepath.Base(path)
|
||||
} else {
|
||||
currDir, err := os.Getwd()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("unable to generate a random name as getting current directory failed: %w", err)
|
||||
}
|
||||
retVal = filepath.Base(currDir)
|
||||
}
|
||||
retVal = strings.TrimSpace(util.GetDNS1123Name(strings.ToLower(retVal)))
|
||||
return retVal, nil
|
||||
}
|
||||
|
||||
// GetDefaultComponentName generates a unique component name
|
||||
// Parameters: desired default component name(w/o prefix) and slice of existing component names
|
||||
// Returns: Unique component name and error if any
|
||||
func GetDefaultComponentName(cfg preference.Client, componentPath string, componentType string, existingComponentList ComponentList) (string, error) {
|
||||
var prefix string
|
||||
var err error
|
||||
|
||||
// Get component names from component list
|
||||
var existingComponentNames []string
|
||||
for _, component := range existingComponentList.Items {
|
||||
existingComponentNames = append(existingComponentNames, component.Name)
|
||||
}
|
||||
|
||||
// Create a random generated name for the component to use within Kubernetes
|
||||
prefix, err = GetComponentDir(componentPath)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("unable to generate random component name: %w", err)
|
||||
}
|
||||
prefix = util.TruncateString(prefix, componentRandomNamePartsMaxLen)
|
||||
|
||||
// Generate unique name for the component using prefix and unique random suffix
|
||||
componentName, err := dfutil.GetRandomName(
|
||||
fmt.Sprintf("%s-%s", componentType, prefix),
|
||||
componentNameMaxLen,
|
||||
existingComponentNames,
|
||||
componentNameMaxRetries,
|
||||
)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("unable to generate random component name: %w", err)
|
||||
}
|
||||
|
||||
return util.GetDNS1123Name(componentName), nil
|
||||
}
|
||||
|
||||
// ApplyConfig applies the component config onto component deployment
|
||||
// Parameters:
|
||||
@@ -160,34 +100,6 @@ func List(client kclient.ClientInterface, applicationSelector string) (Component
|
||||
return newComponentList(devfileList.Items), nil
|
||||
}
|
||||
|
||||
// GetComponentFromDevfile extracts component's metadata from the specified env info if it exists
|
||||
func GetComponentFromDevfile(info *envinfo.EnvSpecificInfo) (Component, parser.DevfileObj, error) {
|
||||
if info.Exists() {
|
||||
devfile, err := parser.Parse(info.GetDevfilePath())
|
||||
if err != nil {
|
||||
return Component{}, parser.DevfileObj{}, err
|
||||
}
|
||||
component, err := getComponentFrom(info, GetComponentTypeFromDevfileMetadata(devfile.Data.GetMetadata()))
|
||||
if err != nil {
|
||||
return Component{}, parser.DevfileObj{}, err
|
||||
}
|
||||
components, err := devfile.Data.GetComponents(parsercommon.DevfileOptions{})
|
||||
if err != nil {
|
||||
return Component{}, parser.DevfileObj{}, err
|
||||
}
|
||||
for _, cmp := range components {
|
||||
if cmp.Container != nil {
|
||||
for _, env := range cmp.Container.Env {
|
||||
component.Spec.Env = append(component.Spec.Env, corev1.EnvVar{Name: env.Name, Value: env.Value})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return component, devfile, nil
|
||||
}
|
||||
return Component{}, parser.DevfileObj{}, nil
|
||||
}
|
||||
|
||||
// GetComponentTypeFromDevfileMetadata returns component type from the devfile metadata;
|
||||
// it could either be projectType or language, if neither of them are set, return 'Not available'
|
||||
func GetComponentTypeFromDevfileMetadata(metadata devfile.DevfileMetadata) string {
|
||||
@@ -224,34 +136,6 @@ func GetLanguageFromDevfileMetadata(metadata devfile.DevfileMetadata) string {
|
||||
return language
|
||||
}
|
||||
|
||||
func getComponentFrom(info localConfigProvider.LocalConfigProvider, componentType string) (Component, error) {
|
||||
if info.Exists() {
|
||||
|
||||
component := newComponentWithType(info.GetName(), componentType)
|
||||
|
||||
component.Namespace = info.GetNamespace()
|
||||
|
||||
component.Spec = ComponentSpec{
|
||||
App: info.GetApplication(),
|
||||
Type: componentType,
|
||||
Ports: []string{fmt.Sprintf("%d", info.GetDebugPort())},
|
||||
}
|
||||
|
||||
urls, err := info.ListURLs()
|
||||
if err != nil {
|
||||
return Component{}, err
|
||||
}
|
||||
if len(urls) > 0 {
|
||||
for _, url := range urls {
|
||||
component.Spec.URL = append(component.Spec.URL, url.Name)
|
||||
}
|
||||
}
|
||||
|
||||
return component, nil
|
||||
}
|
||||
return Component{}, nil
|
||||
}
|
||||
|
||||
func ListDevfileStacksInPath(client kclient.ClientInterface, paths []string) ([]Component, error) {
|
||||
var components []Component
|
||||
var err error
|
||||
@@ -324,18 +208,6 @@ func Exists(client kclient.ClientInterface, componentName, applicationName strin
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func GetComponentState(client kclient.ClientInterface, componentName, applicationName string) string {
|
||||
// Check to see if the deployment has been pushed or not
|
||||
c, err := GetPushedComponent(client, componentName, applicationName)
|
||||
if err != nil {
|
||||
return StateTypeUnknown
|
||||
}
|
||||
if c != nil {
|
||||
return StateTypePushed
|
||||
}
|
||||
return StateTypeNotPushed
|
||||
}
|
||||
|
||||
// GetComponent provides component definition
|
||||
func GetComponent(client kclient.ClientInterface, componentName string, applicationName string, projectName string) (component Component, err error) {
|
||||
return getRemoteComponentMetadata(client, componentName, applicationName, true, true)
|
||||
|
||||
@@ -1,203 +0,0 @@
|
||||
package component
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
v1 "k8s.io/api/apps/v1"
|
||||
|
||||
"github.com/redhat-developer/odo/pkg/kclient"
|
||||
"github.com/redhat-developer/odo/pkg/localConfigProvider"
|
||||
"github.com/redhat-developer/odo/pkg/service"
|
||||
|
||||
devfileParser "github.com/devfile/library/pkg/devfile/parser"
|
||||
"github.com/redhat-developer/odo/pkg/envinfo"
|
||||
"github.com/redhat-developer/odo/pkg/log"
|
||||
"github.com/redhat-developer/odo/pkg/storage"
|
||||
urlpkg "github.com/redhat-developer/odo/pkg/url"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// ComponentFullDescriptionSpec represents the complete description of the component
|
||||
type ComponentFullDescriptionSpec struct {
|
||||
App string `json:"app,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
Source string `json:"source,omitempty"`
|
||||
URL urlpkg.URLList `json:"urls,omitempty"`
|
||||
Storage storage.StorageList `json:"storages,omitempty"`
|
||||
Env []corev1.EnvVar `json:"env,omitempty"`
|
||||
Ports []string `json:"ports,omitempty"`
|
||||
}
|
||||
|
||||
// ComponentFullDescription describes a component fully
|
||||
type ComponentFullDescription struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
Spec ComponentFullDescriptionSpec `json:"spec,omitempty"`
|
||||
Status ComponentStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// copyFromComponentDescription copies over all fields from Component that can be copied
|
||||
func (cfd *ComponentFullDescription) copyFromComponentDesc(component *Component) error {
|
||||
d, err := json.Marshal(component)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return json.Unmarshal(d, cfd)
|
||||
}
|
||||
|
||||
// fillEmptyFields fills any fields that are empty in the ComponentFullDescription
|
||||
func (cfd *ComponentFullDescription) fillEmptyFields(componentDesc Component, componentName string, applicationName string, projectName string) {
|
||||
// fix missing names in case it is in not in description
|
||||
if len(cfd.Name) <= 0 {
|
||||
cfd.Name = componentName
|
||||
}
|
||||
|
||||
if len(cfd.Namespace) <= 0 {
|
||||
cfd.Namespace = projectName
|
||||
}
|
||||
|
||||
if len(cfd.Kind) <= 0 {
|
||||
cfd.Kind = "Component"
|
||||
}
|
||||
|
||||
if len(cfd.APIVersion) <= 0 {
|
||||
cfd.APIVersion = apiVersion
|
||||
}
|
||||
|
||||
if len(cfd.Spec.App) <= 0 {
|
||||
cfd.Spec.App = applicationName
|
||||
}
|
||||
cfd.Spec.Ports = componentDesc.Spec.Ports
|
||||
}
|
||||
|
||||
// NewComponentFullDescriptionFromClientAndLocalConfigProvider gets the complete description of the component from cluster
|
||||
func NewComponentFullDescriptionFromClientAndLocalConfigProvider(client kclient.ClientInterface, envInfo *envinfo.EnvSpecificInfo, componentName string, applicationName string, projectName string, context string) (*ComponentFullDescription, error) {
|
||||
cfd := &ComponentFullDescription{}
|
||||
var state string
|
||||
if client == nil {
|
||||
state = StateTypeUnknown
|
||||
} else {
|
||||
state = GetComponentState(client, componentName, applicationName)
|
||||
}
|
||||
var componentDesc Component
|
||||
var devfile devfileParser.DevfileObj
|
||||
var err error
|
||||
var configLinks []string
|
||||
componentDesc, devfile, err = GetComponentFromDevfile(envInfo)
|
||||
if err != nil {
|
||||
return cfd, err
|
||||
}
|
||||
configLinks, err = service.ListDevfileLinks(devfile, context)
|
||||
|
||||
if err != nil {
|
||||
return cfd, err
|
||||
}
|
||||
err = cfd.copyFromComponentDesc(&componentDesc)
|
||||
if err != nil {
|
||||
return cfd, err
|
||||
}
|
||||
cfd.Status.State = state
|
||||
var deployment *v1.Deployment
|
||||
if state == StateTypePushed {
|
||||
componentDescFromCluster, e := getRemoteComponentMetadata(client, componentName, applicationName, false, false)
|
||||
if e != nil {
|
||||
return cfd, e
|
||||
}
|
||||
cfd.Spec.Env = componentDescFromCluster.Spec.Env
|
||||
cfd.Spec.Type = componentDescFromCluster.Spec.Type
|
||||
cfd.Status.LinkedServices = componentDescFromCluster.Status.LinkedServices
|
||||
// Obtain the deployment to correctly instantiate the Storage and URL client and get information
|
||||
deployment, err = client.GetOneDeployment(componentName, applicationName)
|
||||
if err != nil {
|
||||
// ideally the error should not occur since we have already established that the component exists on the cluster
|
||||
return cfd, err
|
||||
}
|
||||
}
|
||||
|
||||
for _, link := range configLinks {
|
||||
found := false
|
||||
for _, linked := range cfd.Status.LinkedServices {
|
||||
if linked.ServiceName == link {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
cfd.Status.LinkedServices = append(cfd.Status.LinkedServices, SecretMount{
|
||||
ServiceName: link,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
cfd.fillEmptyFields(componentDesc, componentName, applicationName, projectName)
|
||||
|
||||
var urls urlpkg.URLList
|
||||
|
||||
var routeSupported bool
|
||||
var e error
|
||||
if client == nil {
|
||||
routeSupported = false
|
||||
} else {
|
||||
routeSupported, e = client.IsRouteSupported()
|
||||
if e != nil {
|
||||
// we assume if there was an error then the cluster is not connected
|
||||
routeSupported = false
|
||||
}
|
||||
}
|
||||
|
||||
var configProvider localConfigProvider.LocalConfigProvider
|
||||
envInfo.SetDevfileObj(devfile)
|
||||
configProvider = envInfo
|
||||
|
||||
urlClient := urlpkg.NewClient(urlpkg.ClientOptions{
|
||||
LocalConfigProvider: configProvider,
|
||||
Client: client,
|
||||
IsRouteSupported: routeSupported,
|
||||
Deployment: deployment,
|
||||
})
|
||||
|
||||
urls, err = urlClient.List()
|
||||
if err != nil {
|
||||
log.Warningf("URLs couldn't not be retrieved: %v", err)
|
||||
}
|
||||
cfd.Spec.URL = urls
|
||||
|
||||
// Obtain Storage information
|
||||
var storages storage.StorageList
|
||||
storageClient := storage.NewClient(storage.ClientOptions{
|
||||
Client: client,
|
||||
LocalConfigProvider: envInfo,
|
||||
Deployment: deployment,
|
||||
})
|
||||
|
||||
// We explicitly do not fill in Spec.Storage for describe because,
|
||||
// it is essentially a list of Storage names, which seems redundant when the detailed StorageSpec is available
|
||||
storages, err = storageClient.List()
|
||||
if err != nil {
|
||||
log.Warningf("Storages couldn't not be retrieved: %v", err)
|
||||
}
|
||||
cfd.Spec.Storage = storages
|
||||
|
||||
return cfd, nil
|
||||
}
|
||||
|
||||
// GetComponent returns a component representation
|
||||
func (cfd *ComponentFullDescription) GetComponent() Component {
|
||||
cmp := NewComponent(cfd.Name)
|
||||
cmp.Spec.App = cfd.Spec.App
|
||||
cmp.Spec.Ports = cfd.Spec.Ports
|
||||
cmp.Spec.Type = cfd.Spec.Type
|
||||
cmp.Spec.StorageSpec = cfd.Spec.Storage.Items
|
||||
cmp.Spec.URLSpec = cfd.Spec.URL.Items
|
||||
for _, url := range cfd.Spec.URL.Items {
|
||||
cmp.Spec.URL = append(cmp.Spec.URL, url.Name)
|
||||
}
|
||||
for _, storage := range cfd.Spec.Storage.Items {
|
||||
cmp.Spec.Storage = append(cmp.Spec.URL, storage.Name)
|
||||
}
|
||||
cmp.ObjectMeta.Namespace = cfd.ObjectMeta.Namespace
|
||||
cmp.Status = cfd.Status
|
||||
cmp.Spec.Env = cfd.Spec.Env
|
||||
return cmp
|
||||
}
|
||||
@@ -3,7 +3,6 @@ package component
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"testing"
|
||||
|
||||
devfilepkg "github.com/devfile/api/v2/pkg/devfile"
|
||||
@@ -12,12 +11,9 @@ import (
|
||||
v1 "k8s.io/api/apps/v1"
|
||||
|
||||
"github.com/devfile/library/pkg/util"
|
||||
"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/localConfigProvider"
|
||||
"github.com/redhat-developer/odo/pkg/preference"
|
||||
"github.com/redhat-developer/odo/pkg/testingutil"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -25,122 +21,6 @@ import (
|
||||
ktesting "k8s.io/client-go/testing"
|
||||
)
|
||||
|
||||
func TestGetComponentFrom(t *testing.T) {
|
||||
type cmpSetting struct {
|
||||
componentName string
|
||||
project string
|
||||
applicationName string
|
||||
debugPort int
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
isEnvInfo bool
|
||||
componentType string
|
||||
envURL []localConfigProvider.LocalURL
|
||||
cmpSetting cmpSetting
|
||||
want Component
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Case 1: Get component when env info file exists",
|
||||
isEnvInfo: true,
|
||||
componentType: "nodejs",
|
||||
envURL: []localConfigProvider.LocalURL{
|
||||
{
|
||||
Name: "url1",
|
||||
},
|
||||
},
|
||||
cmpSetting: cmpSetting{
|
||||
componentName: "frontend",
|
||||
project: "project1",
|
||||
applicationName: "testing",
|
||||
debugPort: 1234,
|
||||
},
|
||||
want: Component{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "Component",
|
||||
APIVersion: "odo.dev/v1alpha1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "frontend",
|
||||
},
|
||||
Spec: ComponentSpec{
|
||||
Type: "nodejs",
|
||||
},
|
||||
Status: ComponentStatus{},
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
name: "Case 2: Get component when env info file does not exists",
|
||||
isEnvInfo: false,
|
||||
componentType: "nodejs",
|
||||
envURL: []localConfigProvider.LocalURL{
|
||||
{
|
||||
Name: "url2",
|
||||
},
|
||||
},
|
||||
cmpSetting: cmpSetting{
|
||||
componentName: "backend",
|
||||
project: "project2",
|
||||
applicationName: "app1",
|
||||
debugPort: 5896,
|
||||
},
|
||||
want: Component{},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
mockLocalConfigProvider := localConfigProvider.NewMockLocalConfigProvider(ctrl)
|
||||
|
||||
mockLocalConfigProvider.EXPECT().Exists().Return(tt.isEnvInfo)
|
||||
|
||||
if tt.isEnvInfo {
|
||||
mockLocalConfigProvider.EXPECT().GetName().Return(tt.cmpSetting.componentName)
|
||||
|
||||
component := newComponentWithType(tt.cmpSetting.componentName, tt.componentType)
|
||||
|
||||
mockLocalConfigProvider.EXPECT().GetNamespace().Return(tt.cmpSetting.project)
|
||||
|
||||
component.Namespace = tt.cmpSetting.project
|
||||
mockLocalConfigProvider.EXPECT().GetApplication().Return(tt.cmpSetting.applicationName)
|
||||
mockLocalConfigProvider.EXPECT().GetDebugPort().Return(tt.cmpSetting.debugPort)
|
||||
|
||||
component.Spec = ComponentSpec{
|
||||
App: tt.cmpSetting.applicationName,
|
||||
Type: tt.componentType,
|
||||
Ports: []string{fmt.Sprintf("%d", tt.cmpSetting.debugPort)},
|
||||
}
|
||||
|
||||
mockLocalConfigProvider.EXPECT().ListURLs().Return(tt.envURL, nil)
|
||||
|
||||
if len(tt.envURL) > 0 {
|
||||
for _, url := range tt.envURL {
|
||||
component.Spec.URL = append(component.Spec.URL, url.Name)
|
||||
}
|
||||
}
|
||||
|
||||
tt.want = component
|
||||
|
||||
}
|
||||
|
||||
got, err := getComponentFrom(mockLocalConfigProvider, tt.componentType)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("getComponentFrom() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("getComponentFrom() = %v, want %v", got, tt.want)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestList(t *testing.T) {
|
||||
deploymentList := v1.DeploymentList{Items: []v1.Deployment{
|
||||
*testingutil.CreateFakeDeployment("comp0"),
|
||||
@@ -231,90 +111,6 @@ func TestList(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetDefaultComponentName(t *testing.T) {
|
||||
tests := []struct {
|
||||
testName string
|
||||
componentType string
|
||||
componentPath string
|
||||
existingComponents ComponentList
|
||||
wantErr bool
|
||||
wantRE string
|
||||
needPrefix bool
|
||||
}{
|
||||
{
|
||||
testName: "Case: App prefix configured",
|
||||
componentType: "nodejs",
|
||||
componentPath: "./testing",
|
||||
existingComponents: ComponentList{},
|
||||
wantErr: false,
|
||||
wantRE: "nodejs-testing-*",
|
||||
needPrefix: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Log("Running test: ", tt.testName)
|
||||
t.Run(tt.testName, func(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
cfg := preference.NewMockClient(ctrl)
|
||||
|
||||
name, err := GetDefaultComponentName(cfg, tt.componentPath, tt.componentType, tt.existingComponents)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("expected err: %v, but err is %v", tt.wantErr, err)
|
||||
}
|
||||
|
||||
r, _ := regexp.Compile(tt.wantRE)
|
||||
match := r.MatchString(name)
|
||||
if !match {
|
||||
t.Errorf("randomly generated application name %s does not match regexp %s", name, tt.wantRE)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetComponentDir(t *testing.T) {
|
||||
type args struct {
|
||||
path string
|
||||
}
|
||||
tests := []struct {
|
||||
testName string
|
||||
args args
|
||||
want string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
testName: "Case: Source Path",
|
||||
args: args{
|
||||
path: "./testing",
|
||||
},
|
||||
wantErr: false,
|
||||
want: "testing",
|
||||
},
|
||||
{
|
||||
testName: "Case: No clue of any component",
|
||||
args: args{
|
||||
path: "",
|
||||
},
|
||||
wantErr: false,
|
||||
want: "component",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Log("Running test: ", tt.testName)
|
||||
t.Run(tt.testName, func(t *testing.T) {
|
||||
name, err := GetComponentDir(tt.args.path)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("expected err: %v, but err is %v", tt.wantErr, err)
|
||||
}
|
||||
|
||||
if name != tt.want {
|
||||
t.Errorf("received name %s which does not match %s", name, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_getMachineReadableFormat(t *testing.T) {
|
||||
type args struct {
|
||||
componentName string
|
||||
|
||||
@@ -6,24 +6,19 @@ import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
devfilev1 "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
|
||||
parsercommon "github.com/devfile/library/pkg/devfile/parser/data/v2/common"
|
||||
|
||||
"github.com/go-git/go-git/v5"
|
||||
"github.com/go-git/go-git/v5/plumbing"
|
||||
"github.com/go-git/go-git/v5/plumbing/transport/http"
|
||||
|
||||
"github.com/redhat-developer/odo/pkg/devfile/location"
|
||||
"github.com/redhat-developer/odo/pkg/log"
|
||||
registryUtil "github.com/redhat-developer/odo/pkg/odo/cli/preference/registry/util"
|
||||
"github.com/redhat-developer/odo/pkg/util"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultStarterProjectName = "devfile-starter-project-name"
|
||||
)
|
||||
|
||||
func checkoutProject(subDir, zipURL, path, starterToken string) error {
|
||||
|
||||
if subDir == "" {
|
||||
@@ -36,43 +31,6 @@ func checkoutProject(subDir, zipURL, path, starterToken string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetStarterProject gets starter project value from flag --starter.
|
||||
func GetStarterProject(projects []devfilev1.StarterProject, projectPassed string) (project *devfilev1.StarterProject, err error) {
|
||||
|
||||
nOfProjects := len(projects)
|
||||
|
||||
if nOfProjects == 0 {
|
||||
return nil, fmt.Errorf("no starter project found in devfile.")
|
||||
}
|
||||
|
||||
// Determine what project to be used
|
||||
if nOfProjects == 1 && projectPassed == defaultStarterProjectName {
|
||||
project = &projects[0]
|
||||
} else if nOfProjects > 1 && projectPassed == defaultStarterProjectName {
|
||||
project = &projects[0]
|
||||
log.Warning("There are multiple projects in this devfile but none have been specified in --starter. Downloading the first: " + project.Name)
|
||||
} else { //If the user has specified a project
|
||||
var availableNames []string
|
||||
|
||||
projectFound := false
|
||||
for indexOfProject, projectInfo := range projects {
|
||||
availableNames = append(availableNames, projectInfo.Name)
|
||||
if projectInfo.Name == projectPassed { //Get the index
|
||||
project = &projects[indexOfProject]
|
||||
projectFound = true
|
||||
}
|
||||
}
|
||||
|
||||
if !projectFound {
|
||||
availableNamesString := strings.Join(availableNames, ",")
|
||||
return nil, fmt.Errorf("the project: %s specified in --starter does not exist, available projects: %s", projectPassed, availableNamesString)
|
||||
}
|
||||
}
|
||||
|
||||
return project, err
|
||||
|
||||
}
|
||||
|
||||
// DownloadStarterProject downloads a starter project referenced in devfile
|
||||
// This will first remove the content of the contextDir
|
||||
func DownloadStarterProject(starterProject *devfilev1.StarterProject, decryptedToken string, contextDir string, verbose bool) error {
|
||||
|
||||
@@ -178,7 +178,6 @@ func odoRootCmd(name, fullName string) *cobra.Command {
|
||||
|
||||
rootCmdList := append([]*cobra.Command{},
|
||||
component.NewCmdComponent(component.RecommendedCommandName, util.GetFullName(fullName, component.RecommendedCommandName)),
|
||||
component.NewCmdCreate(component.CreateRecommendedCommandName, util.GetFullName(fullName, component.CreateRecommendedCommandName)),
|
||||
component.NewCmdList(component.ListRecommendedCommandName, util.GetFullName(fullName, component.ListRecommendedCommandName)),
|
||||
component.NewCmdPush(component.PushRecommendedCommandName, util.GetFullName(fullName, component.PushRecommendedCommandName)),
|
||||
login.NewCmdLogin(login.RecommendedCommandName, util.GetFullName(fullName, login.RecommendedCommandName)),
|
||||
|
||||
@@ -3,10 +3,11 @@ package component
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"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/spf13/cobra"
|
||||
)
|
||||
|
||||
// RecommendedCommandName is the recommended component command name
|
||||
@@ -39,7 +40,6 @@ func (co *ComponentOptions) Complete(cmdline cmdline.Cmdline, args []string) (er
|
||||
func NewCmdComponent(name, fullName string) *cobra.Command {
|
||||
|
||||
componentGetCmd := NewCmdGet(GetRecommendedCommandName, odoutil.GetFullName(fullName, GetRecommendedCommandName))
|
||||
createCmd := NewCmdCreate(CreateRecommendedCommandName, odoutil.GetFullName(fullName, CreateRecommendedCommandName))
|
||||
listCmd := NewCmdList(ListRecommendedCommandName, odoutil.GetFullName(fullName, ListRecommendedCommandName))
|
||||
pushCmd := NewCmdPush(PushRecommendedCommandName, odoutil.GetFullName(fullName, PushRecommendedCommandName))
|
||||
|
||||
@@ -47,8 +47,8 @@ func NewCmdComponent(name, fullName string) *cobra.Command {
|
||||
var componentCmd = &cobra.Command{
|
||||
Use: name,
|
||||
Short: "Manage components",
|
||||
Example: fmt.Sprintf("%s\n%s\n\n See sub-commands individually for more examples",
|
||||
fullName, CreateRecommendedCommandName),
|
||||
Example: fmt.Sprintf("%s\n\n See sub-commands individually for more examples",
|
||||
fullName),
|
||||
// `odo component set/get` and `odo get/set` are respectively deprecated as per the new workflow
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
},
|
||||
@@ -57,7 +57,7 @@ func NewCmdComponent(name, fullName string) *cobra.Command {
|
||||
// add flags from 'get' to component command
|
||||
componentCmd.Flags().AddFlagSet(componentGetCmd.Flags())
|
||||
|
||||
componentCmd.AddCommand(componentGetCmd, createCmd, listCmd, pushCmd)
|
||||
componentCmd.AddCommand(componentGetCmd, listCmd, pushCmd)
|
||||
|
||||
// Add a defined annotation in order to appear in the help menu
|
||||
componentCmd.Annotations = map[string]string{"command": "main"}
|
||||
|
||||
@@ -1,425 +0,0 @@
|
||||
package component
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/zalando/go-keyring"
|
||||
|
||||
odoDevfile "github.com/redhat-developer/odo/pkg/devfile"
|
||||
"github.com/redhat-developer/odo/pkg/devfile/location"
|
||||
"github.com/redhat-developer/odo/pkg/envinfo"
|
||||
"github.com/redhat-developer/odo/pkg/log"
|
||||
registryUtil "github.com/redhat-developer/odo/pkg/odo/cli/preference/registry/util"
|
||||
projectCmd "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/genericclioptions/clientset"
|
||||
odoutil "github.com/redhat-developer/odo/pkg/odo/util"
|
||||
"github.com/redhat-developer/odo/pkg/odo/util/completion"
|
||||
"github.com/redhat-developer/odo/pkg/registry"
|
||||
scontext "github.com/redhat-developer/odo/pkg/segment/context"
|
||||
"github.com/redhat-developer/odo/pkg/util"
|
||||
|
||||
"github.com/devfile/library/pkg/devfile"
|
||||
"github.com/devfile/library/pkg/devfile/parser"
|
||||
dfutil "github.com/devfile/library/pkg/util"
|
||||
|
||||
ktemplates "k8s.io/kubectl/pkg/util/templates"
|
||||
)
|
||||
|
||||
// CreateOptions encapsulates create options
|
||||
type CreateOptions struct {
|
||||
// Push context
|
||||
*PushOptions
|
||||
|
||||
// Flags
|
||||
contextFlag string
|
||||
portFlag []string
|
||||
envFlag []string
|
||||
nowFlag bool
|
||||
appFlag string
|
||||
interactive bool
|
||||
|
||||
// devfileName stores the "componentType" passed by user irrespective of it being a valid componentType
|
||||
// we use it for telemetry
|
||||
devfileName string
|
||||
|
||||
createMethod CreateMethod
|
||||
devfileMetadata DevfileMetadata
|
||||
stackName string
|
||||
}
|
||||
|
||||
// Path of user's own devfile, user specifies the path via --devfile flag
|
||||
type devfilePath struct {
|
||||
protocol string
|
||||
value string
|
||||
}
|
||||
|
||||
// DevfileMetadata includes devfile component metadata
|
||||
type DevfileMetadata struct {
|
||||
componentType string
|
||||
componentName string
|
||||
componentNamespace string
|
||||
devfileLink string
|
||||
devfileRegistry registry.Registry
|
||||
devfilePath devfilePath
|
||||
userCreatedDevfile bool
|
||||
starter string
|
||||
token string
|
||||
starterToken string
|
||||
}
|
||||
|
||||
// CreateRecommendedCommandName is the recommended watch command name
|
||||
const CreateRecommendedCommandName = "create"
|
||||
|
||||
// LocalDirectoryDefaultLocation is the default location of where --local files should always be..
|
||||
// since the application will always be in the same directory as `.odo`, we will always set this as: ./
|
||||
const LocalDirectoryDefaultLocation = "./"
|
||||
|
||||
var (
|
||||
EnvYAMLFilePath = filepath.Join(".odo", "env", "env.yaml")
|
||||
EnvDirectory = filepath.Join(".odo", "env")
|
||||
)
|
||||
|
||||
var createLongDesc = ktemplates.LongDesc(`Create a configuration describing a component.`)
|
||||
|
||||
var createExample = ktemplates.Examples(`# Create a new Node.JS component with existing sourcecode as well as specifying a name
|
||||
%[1]s nodejs mynodejs
|
||||
|
||||
# Name is not required and will be automatically generated if not passed
|
||||
%[1]s nodejs
|
||||
|
||||
# List all available components before deploying
|
||||
odo catalog list components
|
||||
%[1]s java-quarkus
|
||||
|
||||
# Download an example devfile and application before deploying
|
||||
%[1]s nodejs --starter
|
||||
|
||||
# Using a specific devfile
|
||||
%[1]s mynodejs --devfile ./devfile.yaml
|
||||
%[1]s mynodejs --devfile https://raw.githubusercontent.com/odo-devfiles/registry/master/devfiles/nodejs/devfile.yaml
|
||||
|
||||
# Create new Node.js component named 'frontend' with the source in './frontend' directory
|
||||
%[1]s nodejs frontend --context ./frontend
|
||||
|
||||
# Create new Node.js component with custom ports and environment variables
|
||||
%[1]s nodejs --port 8080,8100/tcp,9100/udp --env key=value,key1=value1
|
||||
|
||||
# Create a new Node.js component that is a part of 'myapp' app inside the 'myproject' project
|
||||
%[1]s nodejs --app myapp --project myproject`)
|
||||
|
||||
// NewCreateOptions returns new instance of CreateOptions
|
||||
func NewCreateOptions() *CreateOptions {
|
||||
return &CreateOptions{
|
||||
PushOptions: NewPushOptions(),
|
||||
}
|
||||
}
|
||||
|
||||
func (co *CreateOptions) Complete(cmdline cmdline.Cmdline, args []string) (err error) {
|
||||
// GETTERS
|
||||
// Get context
|
||||
co.Context, err = getContext(co.nowFlag, cmdline)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Get the app name
|
||||
co.appFlag = genericclioptions.ResolveAppFlag(cmdline)
|
||||
// Get the project name
|
||||
co.devfileMetadata.componentNamespace = co.Context.GetProject()
|
||||
// Get DevfilePath
|
||||
co.DevfilePath = location.DevfileLocation(co.contextFlag)
|
||||
//Check whether the directory already contains a devfile, this check should happen early
|
||||
co.devfileMetadata.userCreatedDevfile = util.CheckPathExists(co.DevfilePath)
|
||||
// EnvFilePath is the path of env file for devfile component
|
||||
envFilePath := getEnvFilePath(co.contextFlag)
|
||||
// This is required so that .odo is created in the correct context
|
||||
co.PushOptions.componentContext = co.contextFlag
|
||||
// Use Interactive mode if: 1) no args are passed || 2) the devfile exists || 3) --devfile is used
|
||||
if len(args) == 0 && !util.CheckPathExists(co.DevfilePath) && co.devfileMetadata.devfilePath.value == "" {
|
||||
co.interactive = true
|
||||
}
|
||||
// CONFLICT CHECK
|
||||
// Check if a component exists
|
||||
if util.CheckPathExists(co.DevfilePath) {
|
||||
if util.CheckPathExists(envFilePath) {
|
||||
return errors.New("this directory already contains a component")
|
||||
} else if co.devfileMetadata.devfilePath.value != "" && !dfutil.PathEqual(co.DevfilePath, co.devfileMetadata.devfilePath.value) {
|
||||
//Check if the directory already contains a devfile when --devfile flag is passed
|
||||
return errors.New("this directory already contains a devfile, you can't specify devfile via --devfile")
|
||||
} else if co.devfileMetadata.starter != "" && len(args) == 0 {
|
||||
//if devfile already exists, then don't allow --starter
|
||||
return fmt.Errorf("this directory already has a devfile so you cannot provide a starter. Please remove exisiting devfile and re-create")
|
||||
}
|
||||
}
|
||||
|
||||
// Check if there is a dangling env file; delete the env file if found
|
||||
if util.CheckPathExists(envFilePath) && !util.CheckPathExists(co.DevfilePath) {
|
||||
log.Warningf("Found a dangling env file without a devfile, overwriting it")
|
||||
// Note: if the IF condition seems to have a side-effect, it is better to do the condition check separately, like below
|
||||
err = dfutil.DeletePath(envFilePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize envinfo
|
||||
err = co.InitEnvInfoFromContext()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Fetch the necessary devfile and create the component
|
||||
log.Info("Devfile Object Creation")
|
||||
switch {
|
||||
case co.devfileMetadata.userCreatedDevfile:
|
||||
co.createMethod = UserCreatedDevfileMethod{}
|
||||
case co.devfileMetadata.devfilePath.value != "":
|
||||
//co.devfileName = "" for user provided devfile
|
||||
fileErr := dfutil.ValidateFile(co.devfileMetadata.devfilePath.value)
|
||||
urlErr := util.ValidateURL(co.devfileMetadata.devfilePath.value)
|
||||
if fileErr != nil && urlErr != nil {
|
||||
return fmt.Errorf("the devfile path you specify is invalid with either file error %q or url error %q", fileErr, urlErr)
|
||||
} else if fileErr == nil {
|
||||
co.createMethod = FileCreateMethod{}
|
||||
} else if urlErr == nil {
|
||||
co.createMethod = HTTPCreateMethod{}
|
||||
}
|
||||
case co.interactive:
|
||||
co.createMethod = InteractiveCreateMethod{}
|
||||
default:
|
||||
co.createMethod = DirectCreateMethod{}
|
||||
}
|
||||
err = co.createMethod.CheckConflicts(co, args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = co.createMethod.FetchDevfileAndCreateComponent(co, cmdline, args)
|
||||
if err != nil {
|
||||
co.createMethod.Rollback(co.DevfilePath, co.contextFlag)
|
||||
return err
|
||||
}
|
||||
|
||||
// From this point forward, rollback should be triggered if an error is encountered; rollback should delete all the files that were created by odo
|
||||
defer func() {
|
||||
if err != nil {
|
||||
co.createMethod.Rollback(co.DevfilePath, co.contextFlag)
|
||||
}
|
||||
}()
|
||||
// Set the starter project token if required
|
||||
if co.devfileMetadata.starter != "" {
|
||||
secure := registryUtil.IsSecure(co.clientset.PreferenceClient, co.devfileMetadata.devfileRegistry.Name)
|
||||
if co.devfileMetadata.starterToken == "" && secure {
|
||||
var token string
|
||||
token, err = keyring.Get(fmt.Sprintf("%s%s", dfutil.CredentialPrefix, co.devfileMetadata.devfileRegistry.Name), registryUtil.RegistryUser)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to get secure registry credential from keyring: %w", err)
|
||||
}
|
||||
co.devfileMetadata.starterToken = token
|
||||
}
|
||||
}
|
||||
|
||||
scontext.SetDevfileName(cmdline.Context(), co.devfileName)
|
||||
// Adding component type to telemetry data
|
||||
scontext.SetComponentType(cmdline.Context(), co.devfileMetadata.componentType)
|
||||
if len(args) > 0 {
|
||||
co.stackName = args[0]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (co *CreateOptions) Validate() (err error) {
|
||||
defer func() {
|
||||
if err != nil {
|
||||
co.createMethod.Rollback(co.DevfilePath, co.contextFlag)
|
||||
}
|
||||
}()
|
||||
log.Info("Validation")
|
||||
// Validate if the devfile component name that user wants to create adheres to the k8s naming convention
|
||||
spinner := log.Spinner("Validating if devfile name is correct")
|
||||
defer spinner.End(false)
|
||||
|
||||
err = dfutil.ValidateK8sResourceName("component name", co.devfileMetadata.componentName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
spinner.End(true)
|
||||
|
||||
// Validate if the devfile is compatible with odo; this checks the resolved/flattened version of devfile
|
||||
spinner = log.Spinner("Validating the devfile for odo")
|
||||
defer spinner.End(false)
|
||||
|
||||
_, err = odoDevfile.ParseAndValidateFromFile(co.DevfilePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
spinner.End(true)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (co *CreateOptions) Run() (err error) {
|
||||
defer func() {
|
||||
if err != nil {
|
||||
co.createMethod.Rollback(co.DevfilePath, co.contextFlag)
|
||||
}
|
||||
}()
|
||||
|
||||
devObj, err := devfileParseFromFile(co.DevfilePath, false)
|
||||
if err != nil {
|
||||
return errors.New("Failed to parse the devfile")
|
||||
}
|
||||
|
||||
devfileData, err := ioutil.ReadFile(co.DevfilePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// WARN: Starter Project uses go-git that overrides the directory content, there by deleting the existing devfile.
|
||||
err = decideAndDownloadStarterProject(devObj, co.devfileMetadata.starter, co.devfileMetadata.starterToken, co.interactive, co.contextFlag)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to download project for devfile component: %w", err)
|
||||
}
|
||||
|
||||
//Check if the directory already contains a devfile when starter project is downloaded
|
||||
if co.devfileMetadata.starter != "" && len(co.stackName) > 0 && !(util.CheckPathExists(co.DevfilePath) && co.devfileMetadata.devfilePath.value != "" && !dfutil.PathEqual(co.DevfilePath, co.devfileMetadata.devfilePath.value)) {
|
||||
// TODO: We should not have to rewrite to the file. Fix the starter project.
|
||||
err = ioutil.WriteFile(co.DevfilePath, devfileData, 0644) // #nosec G306
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// If user provided a custom name, re-write the devfile
|
||||
// ENSURE: co.devfileMetadata.componentName != ""
|
||||
if co.devfileMetadata.componentName != devObj.GetMetadataName() {
|
||||
spinner := log.Spinnerf("Updating the devfile with component name %q", co.devfileMetadata.componentName)
|
||||
defer spinner.End(false)
|
||||
|
||||
// WARN: SetMetadataName will rewrite to the devfile
|
||||
err = devObj.SetMetadataName(co.devfileMetadata.componentName)
|
||||
if err != nil {
|
||||
return errors.New("Failed to update the devfile")
|
||||
}
|
||||
spinner.End(true)
|
||||
}
|
||||
|
||||
// Generate env file
|
||||
err = co.EnvSpecificInfo.SetComponentSettings(envinfo.ComponentSettings{
|
||||
Name: co.devfileMetadata.componentName,
|
||||
Project: co.devfileMetadata.componentNamespace,
|
||||
AppName: co.appFlag,
|
||||
UserCreatedDevfile: co.devfileMetadata.userCreatedDevfile,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create env file for devfile component: %w", err)
|
||||
}
|
||||
|
||||
// Prepare .gitignore file
|
||||
sourcePath, err := dfutil.GetAbsPath(co.contextFlag)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to get source path: %w", err)
|
||||
}
|
||||
|
||||
ignoreFile, err := util.TouchGitIgnoreFile(sourcePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = dfutil.AddFileToIgnoreFile(ignoreFile, filepath.Join(co.contextFlag, EnvDirectory))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if co.nowFlag {
|
||||
err = co.DevfilePush()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to push changes: %w", err)
|
||||
}
|
||||
} else {
|
||||
log.Italic("\nPlease use `odo push` command to create the component with source deployed")
|
||||
}
|
||||
|
||||
if log.IsJSON() {
|
||||
return co.DevfileJSON()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewCmdCreate implements the create odo command
|
||||
func NewCmdCreate(name, fullName string) *cobra.Command {
|
||||
co := NewCreateOptions()
|
||||
var componentCreateCmd = &cobra.Command{
|
||||
Use: fmt.Sprintf("%s <component_type> [component_name] [flags]", name),
|
||||
Short: "Create a new component",
|
||||
Long: createLongDesc,
|
||||
Example: fmt.Sprintf(createExample, fullName),
|
||||
Args: cobra.RangeArgs(0, 2),
|
||||
Annotations: map[string]string{"machineoutput": "json", "command": "component"},
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
genericclioptions.GenericRun(co, cmd, args)
|
||||
},
|
||||
}
|
||||
clientset.Add(componentCreateCmd, clientset.PROJECT, clientset.PREFERENCE)
|
||||
|
||||
odoutil.AddContextFlag(componentCreateCmd, &co.contextFlag)
|
||||
componentCreateCmd.Flags().StringSliceVarP(&co.portFlag, "port", "p", []string{}, "Ports to be used when the component is created (ex. 8080,8100/tcp,9100/udp)")
|
||||
componentCreateCmd.Flags().StringSliceVar(&co.envFlag, "env", []string{}, "Environmental variables for the component. For example --env VariableName=Value")
|
||||
|
||||
componentCreateCmd.Flags().StringVar(&co.devfileMetadata.starter, "starter", "", "Download a project specified in the devfile")
|
||||
componentCreateCmd.Flags().StringVar(&co.devfileMetadata.devfileRegistry.Name, "registry", "", "Create devfile component from specific registry")
|
||||
componentCreateCmd.Flags().StringVar(&co.devfileMetadata.devfilePath.value, "devfile", "", "Path to the user specified devfile")
|
||||
componentCreateCmd.Flags().StringVar(&co.devfileMetadata.token, "token", "", "Token to be used when downloading devfile from the devfile path that is specified via --devfile")
|
||||
componentCreateCmd.Flags().StringVar(&co.devfileMetadata.starterToken, "starter-token", "", "Token to be used when downloading starter project")
|
||||
componentCreateCmd.SetFlagErrorFunc(func(command *cobra.Command, err error) error {
|
||||
if strings.Contains(err.Error(), "flag needs an argument: --starter") {
|
||||
return fmt.Errorf("%w: you can get the list of possible values with the command `odo catalog describe component <type>`", err)
|
||||
}
|
||||
return err
|
||||
})
|
||||
|
||||
componentCreateCmd.SetUsageTemplate(odoutil.CmdUsageTemplate)
|
||||
|
||||
// Adding `--now` flag
|
||||
odoutil.AddNowFlag(componentCreateCmd, &co.nowFlag)
|
||||
//Adding `--project` flag
|
||||
projectCmd.AddProjectFlag(componentCreateCmd)
|
||||
|
||||
completion.RegisterCommandHandler(componentCreateCmd, completion.CreateCompletionHandler)
|
||||
completion.RegisterCommandFlagHandler(componentCreateCmd, "context", completion.FileCompletionHandler)
|
||||
completion.RegisterCommandFlagHandler(componentCreateCmd, "binary", completion.FileCompletionHandler)
|
||||
|
||||
return componentCreateCmd
|
||||
}
|
||||
|
||||
func getContext(now bool, cmdline cmdline.Cmdline) (*genericclioptions.Context, error) {
|
||||
params := genericclioptions.NewCreateParameters(cmdline)
|
||||
if now {
|
||||
params = params.CreateAppIfNeeded()
|
||||
} else {
|
||||
params = params.IsOffline()
|
||||
}
|
||||
return genericclioptions.New(params)
|
||||
}
|
||||
|
||||
func getEnvFilePath(componentContext string) string {
|
||||
if componentContext != "" {
|
||||
return filepath.Join(componentContext, EnvYAMLFilePath)
|
||||
}
|
||||
return filepath.Join(LocalDirectoryDefaultLocation, EnvYAMLFilePath)
|
||||
}
|
||||
|
||||
// DevfileParseFromFile reads, parses and validates a devfile from a file without flattening it
|
||||
func devfileParseFromFile(devfilePath string, resolved bool) (parser.DevfileObj, error) {
|
||||
devObj, _, err := devfile.ParseDevfileAndValidate(parser.ParserArgs{Path: devfilePath, FlattenedDevfile: &resolved})
|
||||
if err != nil {
|
||||
return parser.DevfileObj{}, err
|
||||
}
|
||||
|
||||
return devObj, nil
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
package component
|
||||
|
||||
import (
|
||||
devfilev1 "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
|
||||
"github.com/devfile/library/pkg/devfile/parser"
|
||||
parsercommon "github.com/devfile/library/pkg/devfile/parser/data/v2/common"
|
||||
"github.com/redhat-developer/odo/pkg/component"
|
||||
"github.com/redhat-developer/odo/pkg/envinfo"
|
||||
"github.com/redhat-developer/odo/pkg/kclient"
|
||||
"github.com/redhat-developer/odo/pkg/machineoutput"
|
||||
)
|
||||
|
||||
// decideAndDownloadStarterProject decides the starter project from the value passed by the user and
|
||||
// downloads it
|
||||
func decideAndDownloadStarterProject(devObj parser.DevfileObj, projectPassed string, token string, interactive bool, contextDir string) error {
|
||||
if projectPassed == "" && !interactive {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Retrieve starter projects
|
||||
starterProjects, err := devObj.Data.GetStarterProjects(parsercommon.DevfileOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var starterProject *devfilev1.StarterProject
|
||||
if interactive {
|
||||
starterProject = getStarterProjectInteractiveMode(starterProjects)
|
||||
} else {
|
||||
starterProject, err = component.GetStarterProject(starterProjects, projectPassed)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if starterProject == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return component.DownloadStarterProject(starterProject, token, contextDir, true)
|
||||
}
|
||||
|
||||
// DevfileJSON creates the full json description of a devfile component is prints it
|
||||
func (co *CreateOptions) DevfileJSON() error {
|
||||
envInfo, err := envinfo.NewEnvSpecificInfo(co.contextFlag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Ignore the error as we want other information if connection to cluster is not possible
|
||||
var c kclient.ClientInterface
|
||||
client, _ := kclient.New()
|
||||
if client != nil {
|
||||
c = client
|
||||
}
|
||||
cfd, err := component.NewComponentFullDescriptionFromClientAndLocalConfigProvider(c, envInfo, envInfo.GetName(), envInfo.GetApplication(), co.GetProject(), co.GetComponentContext())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
machineoutput.OutputSuccess(cfd.GetComponent())
|
||||
return nil
|
||||
}
|
||||
@@ -1,427 +0,0 @@
|
||||
package component
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/zalando/go-keyring"
|
||||
|
||||
"github.com/redhat-developer/odo/pkg/component"
|
||||
"github.com/redhat-developer/odo/pkg/kclient"
|
||||
"github.com/redhat-developer/odo/pkg/log"
|
||||
"github.com/redhat-developer/odo/pkg/odo/cli/component/ui"
|
||||
registryUtil "github.com/redhat-developer/odo/pkg/odo/cli/preference/registry/util"
|
||||
"github.com/redhat-developer/odo/pkg/odo/cmdline"
|
||||
odoutil "github.com/redhat-developer/odo/pkg/odo/util"
|
||||
"github.com/redhat-developer/odo/pkg/preference"
|
||||
"github.com/redhat-developer/odo/pkg/registry"
|
||||
"github.com/redhat-developer/odo/pkg/segment"
|
||||
"github.com/redhat-developer/odo/pkg/testingutil/filesystem"
|
||||
"github.com/redhat-developer/odo/pkg/util"
|
||||
|
||||
dfutil "github.com/devfile/library/pkg/util"
|
||||
registryLibrary "github.com/devfile/registry-support/registry-library/library"
|
||||
|
||||
"k8s.io/klog"
|
||||
)
|
||||
|
||||
type CreateMethod interface {
|
||||
// CheckConflicts checks for conflicts specific to a create method
|
||||
CheckConflicts(co *CreateOptions, args []string) error
|
||||
// FetchDevfileAndCreateComponent fetches devfile from registry, or a remote location, or a local file system, and creates a component
|
||||
// This method also updates the CreateOptions structure with co.devfileMetadata
|
||||
FetchDevfileAndCreateComponent(co *CreateOptions, cmdline cmdline.Cmdline, args []string) error
|
||||
// Rollback cleans the component context of any files that were created by odo (devfile.yaml, .odo e.g.)
|
||||
Rollback(devfile, componentContext string)
|
||||
}
|
||||
|
||||
// InteractiveCreateMethod is used while creating a component interactively
|
||||
type InteractiveCreateMethod struct{}
|
||||
|
||||
func (icm InteractiveCreateMethod) CheckConflicts(co *CreateOptions, args []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (icm InteractiveCreateMethod) FetchDevfileAndCreateComponent(co *CreateOptions, cmdline cmdline.Cmdline, args []string) error {
|
||||
catalogDevfileList, err := validateAndFetchRegistry(co.devfileMetadata.devfileRegistry.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
//SET METADATA
|
||||
// Component type: We provide devfile component list to let user choose
|
||||
componentType := ui.SelectDevfileComponentType(catalogDevfileList.Items)
|
||||
|
||||
// Component name: User needs to specify the component name, by default it is component type that user chooses
|
||||
componentName := ui.EnterDevfileComponentName(componentType)
|
||||
|
||||
// Component namespace: User needs to specify component namespace, by default it is the current active namespace
|
||||
var componentNamespace string
|
||||
if cmdline.IsFlagSet("project") {
|
||||
componentNamespace, err = cmdline.FlagValue("project")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
var currentNamespace string
|
||||
if co.KClient != nil {
|
||||
// Get the current project if no --project is passed, but --now is passed
|
||||
currentNamespace = co.KClient.GetCurrentProjectName()
|
||||
} else {
|
||||
var client kclient.ClientInterface
|
||||
client, err = kclient.New()
|
||||
// if err != nil, currentNamespace will be an empty string
|
||||
if err == nil && client != nil {
|
||||
// Get the current project if no --project is passed and using offline context
|
||||
currentNamespace = client.GetCurrentProjectName()
|
||||
}
|
||||
}
|
||||
componentNamespace = ui.EnterDevfileComponentProject(currentNamespace)
|
||||
}
|
||||
|
||||
co.devfileMetadata.componentType = componentType
|
||||
co.devfileName = componentType
|
||||
co.devfileMetadata.componentName = componentName
|
||||
co.devfileMetadata.componentNamespace = componentNamespace
|
||||
|
||||
co.devfileMetadata.devfileLink, co.devfileMetadata.devfileRegistry, err = findDevfileFromRegistry(catalogDevfileList, co.devfileMetadata.devfileRegistry.Name, co.devfileMetadata.componentType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return fetchDevfileFromRegistry(co.devfileMetadata.devfileRegistry, co.devfileMetadata.devfileLink, co.DevfilePath, co.devfileMetadata.componentType, co.contextFlag, co.clientset.PreferenceClient)
|
||||
}
|
||||
|
||||
func (icm InteractiveCreateMethod) Rollback(devfile, componentContext string) {
|
||||
deleteDevfile(devfile)
|
||||
deleteOdoDir(componentContext)
|
||||
}
|
||||
|
||||
// DirectCreateMethod is used with the basic odo create; `odo create nodejs mynode`
|
||||
type DirectCreateMethod struct{}
|
||||
|
||||
func (dcm DirectCreateMethod) CheckConflicts(co *CreateOptions, args []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dcm DirectCreateMethod) FetchDevfileAndCreateComponent(co *CreateOptions, cmdline cmdline.Cmdline, args []string) error {
|
||||
catalogDevfileList, err := validateAndFetchRegistry(co.devfileMetadata.devfileRegistry.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// SET METADATA
|
||||
// The first argument passed will always be considered as component type
|
||||
co.devfileMetadata.componentType = args[0]
|
||||
co.devfileName = args[0]
|
||||
|
||||
var componentName string
|
||||
if len(args) == 2 {
|
||||
// If more than one argument is passed, then the second one will be considered as component name
|
||||
componentName = args[1]
|
||||
} else {
|
||||
// If only component type is passed, then the component name will be created by odo
|
||||
componentName, err = createDefaultComponentName(
|
||||
co.devfileMetadata.componentType,
|
||||
co.contextFlag,
|
||||
co.clientset.PreferenceClient,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
co.devfileMetadata.componentName = componentName
|
||||
co.devfileMetadata.devfileLink, co.devfileMetadata.devfileRegistry, err = findDevfileFromRegistry(catalogDevfileList, co.devfileMetadata.devfileRegistry.Name, co.devfileMetadata.componentType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return fetchDevfileFromRegistry(co.devfileMetadata.devfileRegistry, co.devfileMetadata.devfileLink, co.DevfilePath, co.devfileMetadata.componentType, co.contextFlag, co.clientset.PreferenceClient)
|
||||
}
|
||||
|
||||
func (dcm DirectCreateMethod) Rollback(devfile, componentContext string) {
|
||||
deleteDevfile(devfile)
|
||||
deleteOdoDir(componentContext)
|
||||
}
|
||||
|
||||
// UserCreatedDevfileMethod is used when a devfile is present in the context directory
|
||||
type UserCreatedDevfileMethod struct{}
|
||||
|
||||
func (ucdm UserCreatedDevfileMethod) CheckConflicts(co *CreateOptions, args []string) error {
|
||||
// More than one arguments should not be allowed when a devfile exists
|
||||
if len(args) > 1 {
|
||||
return &DevfileExistsExtraArgsError{len(args)}
|
||||
}
|
||||
//Check if the directory already contains a devfile when --devfile flag is passed
|
||||
if co.devfileMetadata.devfilePath.value != "" && !dfutil.PathEqual(co.DevfilePath, co.devfileMetadata.devfilePath.value) {
|
||||
return &DevfileExistsDevfileFlagError{}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ucdm UserCreatedDevfileMethod) FetchDevfileAndCreateComponent(co *CreateOptions, cmdline cmdline.Cmdline, args []string) error {
|
||||
|
||||
// Existing devfile Mode; co.devfileName = ""
|
||||
devfileAbsolutePath, err := filepath.Abs(co.DevfilePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
devfileSpinner := log.Spinnerf("odo will create a devfile component from the existing devfile: %s", devfileAbsolutePath)
|
||||
defer devfileSpinner.End(true)
|
||||
co.devfileMetadata.componentName, co.devfileMetadata.componentType, err = getMetadataForExistingDevfile(co, args)
|
||||
return err
|
||||
}
|
||||
|
||||
func (ucdm UserCreatedDevfileMethod) Rollback(devfile, componentContext string) {
|
||||
deleteOdoDir(componentContext)
|
||||
}
|
||||
|
||||
// HTTPCreateMethod is used when --devfile flag is used with a remote file; `odo create --devfile https://example.com/devfile.yaml`
|
||||
type HTTPCreateMethod struct{}
|
||||
|
||||
func (hcm HTTPCreateMethod) CheckConflicts(co *CreateOptions, args []string) error {
|
||||
return conflictCheckForDevfileFlag(args, co.devfileMetadata.devfileRegistry.Name)
|
||||
}
|
||||
|
||||
func (hcm HTTPCreateMethod) FetchDevfileAndCreateComponent(co *CreateOptions, cmdline cmdline.Cmdline, args []string) error {
|
||||
devfileSpinner := log.Spinnerf("Creating a devfile component from devfile path: %s", co.devfileMetadata.devfilePath.value)
|
||||
defer devfileSpinner.End(false)
|
||||
|
||||
params := dfutil.HTTPRequestParams{
|
||||
URL: co.devfileMetadata.devfilePath.value,
|
||||
Token: co.devfileMetadata.token,
|
||||
}
|
||||
devfileData, err := util.DownloadFileInMemory(params)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to download devfile for devfile component from %s: %w", co.devfileMetadata.devfilePath.value, err)
|
||||
}
|
||||
err = ioutil.WriteFile(co.DevfilePath, devfileData, 0644) // #nosec G306
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to save devfile to %s: %w", co.DevfilePath, err)
|
||||
}
|
||||
devfileSpinner.End(true)
|
||||
|
||||
// SET METADATA
|
||||
co.devfileMetadata.devfilePath.protocol = "http(s)"
|
||||
co.devfileMetadata.componentName, co.devfileMetadata.componentType, err = getMetadataForExistingDevfile(co, args)
|
||||
return err
|
||||
}
|
||||
|
||||
func (hcm HTTPCreateMethod) Rollback(devfile, componentContext string) {
|
||||
deleteDevfile(devfile)
|
||||
deleteOdoDir(componentContext)
|
||||
}
|
||||
|
||||
// FileCreateMethod is used when --devfile flag is used with a local file; `odo create --devfile /tmp/comp/devfile.yaml`
|
||||
type FileCreateMethod struct{}
|
||||
|
||||
func (fcm FileCreateMethod) CheckConflicts(co *CreateOptions, args []string) error {
|
||||
return conflictCheckForDevfileFlag(args, co.devfileMetadata.devfileRegistry.Name)
|
||||
}
|
||||
|
||||
func (fcm FileCreateMethod) FetchDevfileAndCreateComponent(co *CreateOptions, cmdline cmdline.Cmdline, args []string) error {
|
||||
devfileAbsolutePath, err := filepath.Abs(co.devfileMetadata.devfilePath.value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
devfileSpinner := log.Spinnerf("Creating a devfile component from devfile path: %s", devfileAbsolutePath)
|
||||
defer devfileSpinner.End(false)
|
||||
devfileData, err := ioutil.ReadFile(co.devfileMetadata.devfilePath.value)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read devfile from %s: %w", co.devfileMetadata.devfilePath, err)
|
||||
}
|
||||
err = ioutil.WriteFile(co.DevfilePath, devfileData, 0644) // #nosec G306
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to save devfile to %s: %w", co.DevfilePath, err)
|
||||
}
|
||||
devfileSpinner.End(true)
|
||||
|
||||
// SET METADATA
|
||||
co.devfileMetadata.devfilePath.protocol = "file"
|
||||
co.devfileMetadata.componentName, co.devfileMetadata.componentType, err = getMetadataForExistingDevfile(co, args)
|
||||
return err
|
||||
}
|
||||
|
||||
func (fcm FileCreateMethod) Rollback(devfile, componentContext string) {
|
||||
deleteDevfile(devfile)
|
||||
deleteOdoDir(componentContext)
|
||||
}
|
||||
|
||||
// conflictCheckForDevfileFlag checks for the common conflicts while using --devfile flag
|
||||
func conflictCheckForDevfileFlag(args []string, registryName string) error {
|
||||
// More than one arguments should not be allowed when --devfile is used
|
||||
if len(args) > 1 {
|
||||
return &DevfileExistsExtraArgsError{len(args)}
|
||||
}
|
||||
// Check if both --devfile and --registry flag are used, in which case raise an error
|
||||
if registryName != "" {
|
||||
return &DevfileFlagWithRegistryFlagError{}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateAndFetchRegistry validates if the provided registryName exists and returns the devfile listed in the registy;
|
||||
// if the registryName is "", then it returns devfiles of all the available registries
|
||||
func validateAndFetchRegistry(registryName string) (registry.DevfileStackList, error) {
|
||||
// TODO(feloy) Get from DI
|
||||
prefClient, err := preference.NewClient()
|
||||
if err != nil {
|
||||
odoutil.LogErrorAndExit(err, "unable to set preference, something is wrong with odo, kindly raise an issue at https://github.com/redhat-developer/odo/issues/new?template=Bug.md")
|
||||
}
|
||||
registryClient := registry.NewRegistryClient(filesystem.DefaultFs{}, prefClient)
|
||||
|
||||
// Validate if the component type is available
|
||||
if registryName != "" {
|
||||
registryExistSpinner := log.Spinnerf("Checking if the registry %q exists", registryName)
|
||||
defer registryExistSpinner.End(false)
|
||||
registryList, e := registryClient.GetDevfileRegistries(registryName)
|
||||
if e != nil {
|
||||
return registry.DevfileStackList{}, fmt.Errorf("failed to get registry: %w", e)
|
||||
}
|
||||
if len(registryList) == 0 {
|
||||
return registry.DevfileStackList{}, fmt.Errorf("registry %s doesn't exist, please specify a valid registry via --registry", registryName)
|
||||
}
|
||||
registryExistSpinner.End(true)
|
||||
}
|
||||
|
||||
klog.V(4).Infof("Fetching the available devfile components")
|
||||
// Get available devfile components for checking devfile compatibility
|
||||
catalogDevfileList, err := registryClient.ListDevfileStacks(registryName)
|
||||
if err != nil {
|
||||
return registry.DevfileStackList{}, err
|
||||
}
|
||||
|
||||
if registryName != "" && catalogDevfileList.Items == nil {
|
||||
return registry.DevfileStackList{}, fmt.Errorf("can't create devfile component from registry %s", registryName)
|
||||
}
|
||||
|
||||
if len(catalogDevfileList.DevfileRegistries) == 0 {
|
||||
return registry.DevfileStackList{}, errors.New("Registry is empty, please run `odo registry add <registry name> <registry URL>` to add a registry\n")
|
||||
}
|
||||
return catalogDevfileList, nil
|
||||
}
|
||||
|
||||
// findDevfileFromRegistry finds the devfile and returns necessary information related to it
|
||||
func findDevfileFromRegistry(catalogDevfileList registry.DevfileStackList, registryName, componentType string) (devfileLink string, devfileRegistry registry.Registry, err error) {
|
||||
devfileExistSpinner := log.Spinnerf("Checking if the devfile for %q exists on available registries", componentType)
|
||||
defer devfileExistSpinner.End(false)
|
||||
if registryName != "" {
|
||||
devfileExistSpinner = log.Spinnerf("Checking if the devfile for %q exists on registry %q", componentType, registryName)
|
||||
}
|
||||
|
||||
// Find the request devfile from the registry
|
||||
for _, devfileComponent := range catalogDevfileList.Items {
|
||||
if componentType == devfileComponent.Name {
|
||||
devfileExistSpinner.End(true)
|
||||
return devfileComponent.Link, devfileComponent.Registry, nil
|
||||
}
|
||||
}
|
||||
return "", registry.Registry{}, fmt.Errorf("devfile component type %q is not supported, please run `odo catalog list components` for a list of supported devfile component types", componentType)
|
||||
}
|
||||
|
||||
// fetchDevfileFromRegistry fetches the required devfile from the list catalogDevfileList
|
||||
func fetchDevfileFromRegistry(registry registry.Registry, devfileLink, devfilePath, componentType, componentContext string, prefClient preference.Client) (err error) {
|
||||
// Download devfile from registry
|
||||
registrySpinner := log.Spinnerf("Creating a devfile component from registry %q", registry.Name)
|
||||
defer registrySpinner.End(false)
|
||||
|
||||
// For GitHub based registries
|
||||
if registryUtil.IsGitBasedRegistry(registry.URL) {
|
||||
registryUtil.PrintGitRegistryDeprecationWarning()
|
||||
|
||||
params := dfutil.HTTPRequestParams{
|
||||
URL: registry.URL + devfileLink,
|
||||
}
|
||||
|
||||
secure := registryUtil.IsSecure(prefClient, registry.Name)
|
||||
if secure {
|
||||
var token string
|
||||
token, err = keyring.Get(fmt.Sprintf("%s%s", dfutil.CredentialPrefix, registry.Name), registryUtil.RegistryUser)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to get secure registry credential from keyring: %w", err)
|
||||
}
|
||||
params.Token = token
|
||||
}
|
||||
|
||||
devfileData, err := util.DownloadFileInMemoryWithCache(params, prefClient.GetRegistryCacheTime())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = ioutil.WriteFile(devfilePath, devfileData, 0644) // #nosec G306
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
err := registryLibrary.PullStackFromRegistry(registry.URL, componentType, componentContext, segment.GetRegistryOptions())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
registrySpinner.End(true)
|
||||
return nil
|
||||
}
|
||||
|
||||
// getMetadataForExistingDevfile sets metadata for a user provided devfile; UserCreatedDevfileCreateMethod, HTTPCreateMethod, and FileCreateMethod
|
||||
func getMetadataForExistingDevfile(co *CreateOptions, args []string) (componentName, componentType string, err error) {
|
||||
devObj, err := devfileParseFromFile(co.DevfilePath, false)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
componentType = component.GetComponentTypeFromDevfileMetadata(devObj.Data.GetMetadata())
|
||||
|
||||
// Set component name
|
||||
if len(args) > 0 {
|
||||
// user provided name: `odo create mynode`
|
||||
componentName = args[0]
|
||||
} else {
|
||||
if devObj.GetMetadataName() != "" {
|
||||
// devfile provided name: `.metadata.name`
|
||||
componentName = devObj.GetMetadataName()
|
||||
} else {
|
||||
// default name
|
||||
componentName, err = createDefaultComponentName(co.devfileMetadata.componentType, co.contextFlag, co.clientset.PreferenceClient)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// createDefaultComponentName creates a default unique component name with the help of component context
|
||||
func createDefaultComponentName(componentType string, sourcePath string, prefClient preference.Client) (string, error) {
|
||||
var finalSourcePath string
|
||||
var err error
|
||||
if sourcePath != "" {
|
||||
finalSourcePath, err = filepath.Abs(sourcePath)
|
||||
} else {
|
||||
finalSourcePath, err = os.Getwd()
|
||||
}
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return component.GetDefaultComponentName(
|
||||
prefClient,
|
||||
finalSourcePath,
|
||||
componentType,
|
||||
component.ComponentList{},
|
||||
)
|
||||
}
|
||||
|
||||
// deleteDevfile deletes the devfile if it exists in case of rollback
|
||||
func deleteDevfile(devfile string) {
|
||||
if util.CheckPathExists(devfile) {
|
||||
_ = os.Remove(devfile)
|
||||
}
|
||||
}
|
||||
|
||||
//deleteOdoDir deletes the .odo directory in case of rollback
|
||||
func deleteOdoDir(componentContext string) {
|
||||
odoDir := filepath.Join(componentContext, ".odo")
|
||||
if util.CheckPathExists(odoDir) {
|
||||
_ = dfutil.DeletePath(odoDir)
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package component
|
||||
|
||||
import (
|
||||
devfilev1 "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
|
||||
"github.com/redhat-developer/odo/pkg/odo/cli/component/ui"
|
||||
)
|
||||
|
||||
// getStarterProjectInteractiveMode gets starter project value by asking user in interactive mode.
|
||||
func getStarterProjectInteractiveMode(projects []devfilev1.StarterProject) *devfilev1.StarterProject {
|
||||
projectName := ui.SelectStarterProject(projects)
|
||||
|
||||
// if user do not wish to download starter project or there are no projects in devfile, project name would be empty
|
||||
if projectName == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
var project devfilev1.StarterProject
|
||||
|
||||
for _, value := range projects {
|
||||
if value.Name == projectName {
|
||||
project = value
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return &project
|
||||
}
|
||||
@@ -37,7 +37,10 @@ var _ = Describe("odo devfile supported tests", func() {
|
||||
})
|
||||
|
||||
createStarterProjAndSetDebug := func(component, starter, debugLocalPort string) {
|
||||
helper.Cmd("odo", "create", component, "--starter", starter, "--project", commonVar.Project, componentName, "--context", projectDirPath).ShouldPass()
|
||||
workingDir := helper.Getwd()
|
||||
defer helper.Chdir(workingDir)
|
||||
helper.Chdir(projectDirPath)
|
||||
helper.Cmd("odo", "init", "--name", componentName, "--devfile", component, "--starter", starter).ShouldPass()
|
||||
helper.Cmd("odo", "push", "--context", projectDirPath).ShouldPass()
|
||||
helper.Cmd("odo", "push", "--debug", "--context", projectDirPath).ShouldPass()
|
||||
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
apiVersion: 1.0.0
|
||||
metadata:
|
||||
name: nodejs
|
||||
starterProjects:
|
||||
- name: nodejs-starter
|
||||
subDir: /app/
|
||||
git:
|
||||
remotes:
|
||||
origin: "https://github.com/che-samples/web-nodejs-sample.git"
|
||||
components:
|
||||
- type: dockerimage
|
||||
image: registry.access.redhat.com/ubi8/nodejs-12:1-36
|
||||
endpoints:
|
||||
- name: "3000-tcp"
|
||||
port: 3000
|
||||
alias: runtime
|
||||
env:
|
||||
- name: FOO
|
||||
value: "bar"
|
||||
memoryLimit: 1024Mi
|
||||
mountSources: true
|
||||
commands:
|
||||
- name: build
|
||||
actions:
|
||||
- type: exec
|
||||
component: runtime
|
||||
command: npm install
|
||||
workdir: ${PROJECTS_ROOT}
|
||||
- name: devbuild
|
||||
actions:
|
||||
- type: exec
|
||||
component: runtime
|
||||
command: npm install
|
||||
workdir: ${PROJECTS_ROOT}
|
||||
- name: run
|
||||
actions:
|
||||
- type: exec
|
||||
component: runtime
|
||||
command: npm start
|
||||
workdir: ${PROJECTS_ROOT}
|
||||
- name: devrun
|
||||
actions:
|
||||
- type: exec
|
||||
component: runtime
|
||||
command: npm start
|
||||
workdir: ${PROJECTS_ROOT}
|
||||
50
tests/examples/source/devfiles/nodejs/devfile-with-tag.yaml
Normal file
50
tests/examples/source/devfiles/nodejs/devfile-with-tag.yaml
Normal file
@@ -0,0 +1,50 @@
|
||||
schemaVersion: 2.0.0
|
||||
metadata:
|
||||
name: nodejs
|
||||
starterProjects:
|
||||
- name: nodejs-starter
|
||||
git:
|
||||
remotes:
|
||||
origin: "https://github.com/odo-devfiles/nodejs-ex.git"
|
||||
checkoutFrom:
|
||||
revision: 0.0.1
|
||||
components:
|
||||
- name: runtime
|
||||
container:
|
||||
image: registry.access.redhat.com/ubi8/nodejs-12:1-36
|
||||
memoryLimit: 1024Mi
|
||||
endpoints:
|
||||
- name: "3000-tcp"
|
||||
targetPort: 3000
|
||||
mountSources: true
|
||||
commands:
|
||||
- id: devbuild
|
||||
exec:
|
||||
component: runtime
|
||||
commandLine: npm install
|
||||
workingDir: ${PROJECTS_ROOT}
|
||||
group:
|
||||
kind: build
|
||||
isDefault: true
|
||||
- id: build
|
||||
exec:
|
||||
component: runtime
|
||||
commandLine: npm install
|
||||
workingDir: ${PROJECTS_ROOT}
|
||||
group:
|
||||
kind: build
|
||||
- id: devrun
|
||||
exec:
|
||||
component: runtime
|
||||
commandLine: npm start
|
||||
workingDir: ${PROJECTS_ROOT}
|
||||
group:
|
||||
kind: run
|
||||
isDefault: true
|
||||
- id: run
|
||||
exec:
|
||||
component: runtime
|
||||
commandLine: npm start
|
||||
workingDir: ${PROJECTS_ROOT}
|
||||
group:
|
||||
kind: run
|
||||
@@ -1,9 +1,12 @@
|
||||
package helper
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
"github.com/redhat-developer/odo/pkg/envinfo"
|
||||
)
|
||||
|
||||
@@ -17,3 +20,17 @@ func LocalEnvInfo(context string) *envinfo.EnvSpecificInfo {
|
||||
}
|
||||
return info
|
||||
}
|
||||
|
||||
// CreateLocalEnv creates a .odo/env/env.yaml file
|
||||
// Useful for commands that require this file and cannot create one on their own, for e.g. url, list
|
||||
func CreateLocalEnv(context, compName, projectName string) {
|
||||
var config = fmt.Sprintf(`
|
||||
ComponentSettings:
|
||||
Name: %s
|
||||
Project: %s
|
||||
AppName: app
|
||||
`, compName, projectName)
|
||||
dir := filepath.Join(context, ".odo", "env")
|
||||
MakeDir(dir)
|
||||
Expect(ioutil.WriteFile(filepath.Join(dir, "env.yaml"), []byte(config), 0600)).To(BeNil())
|
||||
}
|
||||
|
||||
@@ -274,18 +274,6 @@ func VerifyFileExists(filename string) bool {
|
||||
return !info.IsDir()
|
||||
}
|
||||
|
||||
// VerifyFilesExist receives an array of paths to files, and returns whether
|
||||
// or not they all exist. If any one of the expected files doesn't exist, it
|
||||
// returns false
|
||||
func VerifyFilesExist(path string, files []string) bool {
|
||||
for _, f := range files {
|
||||
if !VerifyFileExists(filepath.Join(path, f)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// ReplaceDevfileField replaces the value of a given field in a specified
|
||||
// devfile.
|
||||
// Currently only the first match of the field is replaced. i.e if the
|
||||
|
||||
@@ -457,27 +457,8 @@ type ResourceInfo struct {
|
||||
Namespace string
|
||||
}
|
||||
|
||||
func VerifyResourcesDeleted(runner CliRunner, resources []ResourceInfo) {
|
||||
for _, item := range resources {
|
||||
runner.VerifyResourceDeleted(item)
|
||||
}
|
||||
}
|
||||
|
||||
func VerifyResourcesToBeDeleted(runner CliRunner, resources []ResourceInfo) {
|
||||
for _, item := range resources {
|
||||
runner.VerifyResourceToBeDeleted(item)
|
||||
}
|
||||
}
|
||||
|
||||
func SetDefaultDevfileRegistryAsStaging() {
|
||||
const registryName string = "DefaultDevfileRegistry"
|
||||
const addRegistryURL string = "https://registry.stage.devfile.io"
|
||||
Cmd("odo", "preference", "registry", "update", registryName, addRegistryURL, "-f").ShouldPass()
|
||||
}
|
||||
|
||||
// CopyAndCreate copies required source code and devfile to the given context directory, and creates a component
|
||||
func CopyAndCreate(sourcePath, devfilePath, contextDir string) {
|
||||
CopyExample(sourcePath, contextDir)
|
||||
CopyExampleDevFile(devfilePath, filepath.Join(contextDir, "devfile.yaml"))
|
||||
Cmd("odo", "create", "--context", contextDir).ShouldPass()
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ var _ = Describe("odo preference and config command tests", func() {
|
||||
})
|
||||
|
||||
It("should not prompt when user calls for help", func() {
|
||||
output := helper.Cmd("odo", "create", "--help").ShouldPass().Out()
|
||||
output := helper.Cmd("odo", "init", "--help").ShouldPass().Out()
|
||||
Expect(output).ToNot(ContainSubstring(promptMessageSubString))
|
||||
})
|
||||
|
||||
@@ -132,9 +132,17 @@ var _ = Describe("odo preference and config command tests", func() {
|
||||
|
||||
Context("When ConsentTelemetry preference value is set", func() {
|
||||
// !! Do not test with true because it sends out the telemetry data and messes up the statistics !!
|
||||
var workingDir string
|
||||
BeforeEach(func() {
|
||||
workingDir = helper.Getwd()
|
||||
helper.Chdir(commonVar.Context)
|
||||
})
|
||||
AfterEach(func() {
|
||||
helper.Chdir(workingDir)
|
||||
})
|
||||
It("should not prompt the user", func() {
|
||||
helper.Cmd("odo", "preference", "set", "ConsentTelemetry", "false", "-f").ShouldPass()
|
||||
output := helper.Cmd("odo", "create", "--context", commonVar.Context, "--devfile", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile-registry.yaml")).ShouldPass().Out()
|
||||
output := helper.Cmd("odo", "init", "--name", "aname", "--devfile-path", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile-registry.yaml")).ShouldPass().Out()
|
||||
Expect(output).ToNot(ContainSubstring(promptMessageSubString))
|
||||
})
|
||||
})
|
||||
|
||||
@@ -36,7 +36,6 @@ var _ = Describe("odo delete command tests", func() {
|
||||
deploymentName = "my-component"
|
||||
serviceName = "my-cs"
|
||||
helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), commonVar.Context)
|
||||
helper.Cmd("odo", "project", "set", commonVar.Project).ShouldPass()
|
||||
helper.Cmd("odo", "init", "--name", cmpName, "--devfile-path", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile-deploy-with-multiple-resources.yaml")).ShouldPass()
|
||||
// Note: component will be automatically bootstrapped when `odo dev` or `odo deploy` is run
|
||||
})
|
||||
@@ -236,7 +235,6 @@ ComponentSettings:
|
||||
// Hardcoded names from devfile-with-valid-events.yaml
|
||||
cmpName = "nodejs"
|
||||
helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), commonVar.Context)
|
||||
helper.Cmd("odo", "project", "set", commonVar.Project).ShouldPass()
|
||||
helper.Cmd("odo", "init", "--name", cmpName, "--devfile-path", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile-with-valid-events.yaml")).ShouldPass()
|
||||
session := helper.CmdRunner("odo", "dev")
|
||||
defer session.Kill()
|
||||
|
||||
@@ -47,7 +47,6 @@ var _ = Describe("odo dev command tests", func() {
|
||||
When("a component is bootstrapped and pushed", func() {
|
||||
BeforeEach(func() {
|
||||
helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), commonVar.Context)
|
||||
helper.Cmd("odo", "project", "set", commonVar.Project).ShouldPass()
|
||||
helper.Cmd("odo", "init", "--name", cmpName, "--devfile-path", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile.yaml")).ShouldPass()
|
||||
Expect(helper.VerifyFileExists(".odo/env/env.yaml")).To(BeFalse())
|
||||
})
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package devfile
|
||||
|
||||
import (
|
||||
"path"
|
||||
"path/filepath"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
"github.com/redhat-developer/odo/tests/helper"
|
||||
)
|
||||
|
||||
@@ -27,9 +27,8 @@ var _ = Describe("odo devfile build-images command tests", func() {
|
||||
|
||||
BeforeEach(func() {
|
||||
helper.CopyExample(filepath.Join("source", "nodejs"), commonVar.Context)
|
||||
helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile-outerloop.yaml"), path.Join(commonVar.Context, "devfile.yaml"))
|
||||
helper.Cmd("odo", "create").ShouldPass()
|
||||
|
||||
helper.Cmd("odo", "init", "--name", "aname", "--devfile-path", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile-outerloop.yaml")).ShouldPass()
|
||||
helper.CreateLocalEnv(commonVar.Context, "aname", commonVar.Project)
|
||||
})
|
||||
It("should run odo build-images without push", func() {
|
||||
stdout := helper.Cmd("odo", "build-images").AddEnv("PODMAN_CMD=echo").ShouldPass().Out()
|
||||
@@ -46,8 +45,8 @@ var _ = Describe("odo devfile build-images command tests", func() {
|
||||
When("using a devfile.yaml containing an Image component with Dockerfile args", func() {
|
||||
BeforeEach(func() {
|
||||
helper.CopyExample(filepath.Join("source", "nodejs"), commonVar.Context)
|
||||
helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile-outerloop-args.yaml"), path.Join(commonVar.Context, "devfile.yaml"))
|
||||
helper.Cmd("odo", "create").ShouldPass()
|
||||
helper.Cmd("odo", "init", "--name", "aname", "--devfile-path", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile-outerloop-args.yaml")).ShouldPass()
|
||||
helper.CreateLocalEnv(commonVar.Context, "aname", commonVar.Project)
|
||||
})
|
||||
|
||||
It("should use args to build image when running odo build-images", func() {
|
||||
|
||||
@@ -1,425 +0,0 @@
|
||||
package devfile
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
|
||||
"github.com/redhat-developer/odo/tests/helper"
|
||||
|
||||
"github.com/tidwall/gjson"
|
||||
"gopkg.in/yaml.v2"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/redhat-developer/odo/pkg/util"
|
||||
)
|
||||
|
||||
var _ = Describe("odo devfile create command tests", func() {
|
||||
const devfile = "devfile.yaml"
|
||||
const envFile = ".odo/env/env.yaml"
|
||||
var contextDevfile, cmpName, devfilePath string
|
||||
var commonVar helper.CommonVar
|
||||
|
||||
var _ = BeforeEach(func() {
|
||||
cmpName = helper.RandString(6)
|
||||
commonVar = helper.CommonBeforeEach()
|
||||
helper.Chdir(commonVar.Context)
|
||||
})
|
||||
|
||||
var _ = AfterEach(func() {
|
||||
helper.CommonAfterEach(commonVar)
|
||||
})
|
||||
|
||||
// checkNodeJSDirContent checks if the required nodejs files are present in the context directory after odo create
|
||||
var checkNodeJSDirContent = func(contextDir string) {
|
||||
expectedFiles := []string{"package.json", "package-lock.json", "README.md", devfile}
|
||||
Expect(helper.VerifyFilesExist(contextDir, expectedFiles)).To(Equal(true))
|
||||
}
|
||||
|
||||
It("should check that .odo/env exists in gitignore", func() {
|
||||
helper.Cmd("odo", "create", "nodejs", "--project", commonVar.Project, cmpName).ShouldPass()
|
||||
ignoreFilePath := filepath.Join(commonVar.Context, ".gitignore")
|
||||
helper.FileShouldContainSubstring(ignoreFilePath, filepath.Join(".odo", "env"))
|
||||
})
|
||||
|
||||
It("should successfully create the devfile component with valid component name", func() {
|
||||
helper.Cmd("odo", "create", "java-openliberty", cmpName).ShouldPass()
|
||||
|
||||
By("checking that component name and language is set correctly in the devfile", func() {
|
||||
metadata := helper.GetMetadataFromDevfile(filepath.Join(commonVar.Context, "devfile.yaml"))
|
||||
Expect(metadata.Name).To(BeEquivalentTo(cmpName))
|
||||
Expect(metadata.Language).To(ContainSubstring("java"))
|
||||
})
|
||||
})
|
||||
|
||||
It("should fail to create the devfile component with invalid component type", func() {
|
||||
fakeComponentName := "fake-component"
|
||||
output := helper.Cmd("odo", "create", fakeComponentName).ShouldFail().Err()
|
||||
expectedString := "component type \"" + fakeComponentName + "\" is not supported"
|
||||
Expect(output).To(ContainSubstring(expectedString))
|
||||
})
|
||||
|
||||
It("should successfully create the devfile component with --project flag", func() {
|
||||
componentNamespace := helper.RandString(6)
|
||||
helper.Cmd("odo", "create", "java-openliberty", "--project", componentNamespace).ShouldPass()
|
||||
fileContents, err := helper.ReadFile(filepath.Join(commonVar.Context, ".odo/env/env.yaml"))
|
||||
Expect(err).To(BeNil())
|
||||
Expect(fileContents).To(ContainSubstring(componentNamespace))
|
||||
})
|
||||
|
||||
When("odo create is executed with the --registry flag", func() {
|
||||
It("should successfully create the devfile component if specified registry is valid", func() {
|
||||
componentRegistry := "DefaultDevfileRegistry"
|
||||
helper.Cmd("odo", "create", "java-openliberty", "--registry", componentRegistry).ShouldPass()
|
||||
})
|
||||
|
||||
It("should fail to create the devfile component if specified registry is invalid", func() {
|
||||
componentRegistry := "fake"
|
||||
output := helper.Cmd("odo", "create", "java-openliberty", "--registry", componentRegistry).ShouldFail().Err()
|
||||
helper.MatchAllInOutput(output, []string{"registry fake doesn't exist, please specify a valid registry via --registry"})
|
||||
})
|
||||
})
|
||||
|
||||
When("odo create is executed with the --context flag", func() {
|
||||
var newContext, envFilePath string
|
||||
BeforeEach(func() {
|
||||
newContext = filepath.Join(commonVar.Context, "newContext")
|
||||
helper.MakeDir(newContext)
|
||||
devfilePath = filepath.Join(newContext, devfile)
|
||||
envFilePath = filepath.Join(newContext, envFile)
|
||||
helper.CopyExample(filepath.Join("source", "nodejs"), newContext)
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
helper.DeleteDir(newContext)
|
||||
})
|
||||
|
||||
It("should successfully create the devfile component in the context", func() {
|
||||
helper.Cmd("odo", "create", "nodejs", "--context", newContext).ShouldPass()
|
||||
|
||||
By("checking the devfile and env file exists", func() {
|
||||
Expect(util.CheckPathExists(devfilePath)).Should(BeTrue())
|
||||
Expect(util.CheckPathExists(envFilePath)).Should(BeTrue())
|
||||
})
|
||||
})
|
||||
|
||||
It("should successfully create the devfile component and download the source in the context when used with --starter flag", func() {
|
||||
helper.Cmd("odo", "create", "nodejs", "--starter", "nodejs-starter", "--context", newContext).ShouldPass()
|
||||
checkNodeJSDirContent(newContext)
|
||||
})
|
||||
|
||||
It("should successfully create the devfile component and show json output", func() {
|
||||
output := helper.Cmd("odo", "create", "nodejs", "--context", newContext, "-o", "json").ShouldPass().Out()
|
||||
values := gjson.GetMany(output, "kind", "metadata.name", "status.state")
|
||||
Expect(helper.GjsonMatcher(values, []string{"Component", "nodejs", "Not Pushed"})).To(Equal(true))
|
||||
})
|
||||
|
||||
It("should successfully create and push the devfile component with --now and show json output", func() {
|
||||
output := helper.Cmd("odo", "create", "nodejs", "--starter", "nodejs-starter", "--context", newContext, "-o", "json", "--now").ShouldPass().Out()
|
||||
checkNodeJSDirContent(newContext)
|
||||
helper.MatchAllInOutput(output, []string{"Pushed", "nodejs", "Component"})
|
||||
})
|
||||
|
||||
It("should successfully create the devfile component and show json output for non connected cluster", func() {
|
||||
output := helper.Cmd("odo", "create", "nodejs", "--context", newContext, "-o", "json").WithEnv("KUBECONFIG=/no/such/path", "GLOBALODOCONFIG="+os.Getenv("GLOBALODOCONFIG")).ShouldPass().Out()
|
||||
values := gjson.GetMany(output, "kind", "metadata.name", "status.state")
|
||||
Expect(helper.GjsonMatcher(values, []string{"Component", "nodejs", "Unknown"})).To(Equal(true))
|
||||
})
|
||||
|
||||
When("the cluster is unreachable", func() {
|
||||
var newKubeConfigPath string
|
||||
BeforeEach(func() {
|
||||
path := os.Getenv("KUBECONFIG")
|
||||
|
||||
// read the contents from the kubeconfig and replace the server entries
|
||||
reg := regexp.MustCompile(`server: .*`)
|
||||
kubeConfigContents, err := helper.ReadFile(path)
|
||||
Expect(err).To(BeNil())
|
||||
kubeConfigContents = reg.ReplaceAllString(kubeConfigContents, "server: https://not-reachable.com:443")
|
||||
|
||||
// write to a new file which will be used as the new kubeconfig
|
||||
newKubeConfigPath = filepath.Join(commonVar.Context, "newKUBECONFIG")
|
||||
newKubeConfig, err := os.Create(newKubeConfigPath)
|
||||
Expect(err).To(BeNil())
|
||||
defer newKubeConfig.Close()
|
||||
|
||||
_, err = newKubeConfig.WriteString(kubeConfigContents)
|
||||
Expect(err).To(BeNil())
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
os.Remove(newKubeConfigPath)
|
||||
})
|
||||
|
||||
It("should successfully create the devfile component and show json output", func() {
|
||||
output := helper.Cmd("odo", "create", "nodejs", "--context", newContext, "-o", "json").WithEnv("KUBECONFIG="+newKubeConfigPath, "GLOBALODOCONFIG="+os.Getenv("GLOBALODOCONFIG")).ShouldPass().Out()
|
||||
values := gjson.GetMany(output, "kind", "metadata.name", "status.state")
|
||||
Expect(helper.GjsonMatcher(values, []string{"Component", "nodejs", "Unknown"})).To(Equal(true))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
When("odo create is executed with the --now flag", func() {
|
||||
BeforeEach(func() {
|
||||
helper.CopyExample(filepath.Join("source", "nodejs"), commonVar.Context)
|
||||
})
|
||||
|
||||
It("checks that odo push works with a devfile with now flag", func() {
|
||||
output := helper.Cmd("odo", "create", "nodejs", "--now").ShouldPass().Out()
|
||||
Expect(output).To(ContainSubstring("Changes successfully pushed to component"))
|
||||
})
|
||||
})
|
||||
|
||||
When("odo create is executed with the --starter flag", func() {
|
||||
BeforeEach(func() {
|
||||
contextDevfile = helper.CreateNewContext()
|
||||
helper.Chdir(contextDevfile)
|
||||
devfilePath = filepath.Join(contextDevfile, devfile)
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
helper.Chdir(commonVar.Context)
|
||||
helper.DeleteDir(contextDevfile)
|
||||
})
|
||||
|
||||
It("should successfully create the component and download the source", func() {
|
||||
helper.Cmd("odo", "create", "nodejs", "--starter", "nodejs-starter").ShouldPass()
|
||||
checkNodeJSDirContent(contextDevfile)
|
||||
})
|
||||
|
||||
It("should fail to create the component when an invalid starter project is specified", func() {
|
||||
invalidProjectName := "invalid-project-name"
|
||||
output := helper.Cmd("odo", "create", "nodejs", "--starter=invalid-project-name").ShouldFail().Err()
|
||||
expectedString := "the project: " + invalidProjectName + " specified in --starter does not exist"
|
||||
helper.MatchAllInOutput(output, []string{expectedString, "available projects", "nodejs-starter"})
|
||||
})
|
||||
|
||||
When("the starter project has git tag or git branch specified", func() {
|
||||
BeforeEach(func() {
|
||||
helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile-with-branch.yaml"), devfilePath)
|
||||
})
|
||||
|
||||
It("should successfully create the component and download the source from the specified branch", func() {
|
||||
helper.Cmd("odo", "create", "nodejs", "--starter", "nodejs-starter").ShouldPass()
|
||||
checkNodeJSDirContent(contextDevfile)
|
||||
})
|
||||
|
||||
It("should successfully create the component and download the source from the specified tag", func() {
|
||||
helper.ReplaceString(devfilePath, "revision: test-branch", "revision: 0.0.1")
|
||||
helper.Cmd("odo", "create", "nodejs", "--starter", "nodejs-starter").ShouldPass()
|
||||
checkNodeJSDirContent(contextDevfile)
|
||||
})
|
||||
})
|
||||
|
||||
When("the starter project has subDir", func() {
|
||||
BeforeEach(func() {
|
||||
helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "springboot", "devfile-with-subDir.yaml"), devfilePath)
|
||||
helper.CopyExample(filepath.Join("source", "devfiles", "springboot", "project"), commonVar.Context)
|
||||
})
|
||||
|
||||
It("should successfully create the component and extract the project in the specified subDir path", func() {
|
||||
var found, notToBeFound int
|
||||
helper.Cmd("odo", "create", "java-springboot", "--project", commonVar.Project, "--starter", "springbootproject").ShouldPass()
|
||||
pathsToValidate := map[string]bool{
|
||||
filepath.Join(contextDevfile, "java", "com"): true,
|
||||
filepath.Join(contextDevfile, "java", "com", "example"): true,
|
||||
filepath.Join(contextDevfile, "java", "com", "example", "demo"): true,
|
||||
filepath.Join(contextDevfile, "java", "com", "example", "demo", "DemoApplication.java"): true,
|
||||
filepath.Join(contextDevfile, "resources", "application.properties"): true,
|
||||
}
|
||||
pathsNotToBePresent := map[string]bool{
|
||||
filepath.Join(contextDevfile, "src"): true,
|
||||
filepath.Join(contextDevfile, "main"): true,
|
||||
}
|
||||
err := filepath.Walk(contextDevfile, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if ok := pathsToValidate[path]; ok {
|
||||
found++
|
||||
}
|
||||
if ok := pathsNotToBePresent[path]; ok {
|
||||
notToBeFound++
|
||||
}
|
||||
return nil
|
||||
})
|
||||
Expect(err).To(BeNil())
|
||||
|
||||
Expect(found).To(Equal(len(pathsToValidate)))
|
||||
Expect(notToBeFound).To(Equal(0))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
When("devfile exists in the working directory", func() {
|
||||
BeforeEach(func() {
|
||||
devfilePath = filepath.Join(commonVar.Context, devfile)
|
||||
helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", devfile), devfilePath)
|
||||
})
|
||||
It("should successfully create the devfile component", func() {
|
||||
helper.Cmd("odo", "create", "nodejs").ShouldPass()
|
||||
})
|
||||
|
||||
It("should successfully create the devfile component with --devfile points to the same devfile", func() {
|
||||
helper.Cmd("odo", "create", "nodejs", "--devfile", "./devfile.yaml").ShouldPass()
|
||||
fileIsEmpty, err := helper.FileIsEmpty("./devfile.yaml")
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(fileIsEmpty).Should(BeFalse())
|
||||
})
|
||||
|
||||
It("should fail to create the devfile component", func() {
|
||||
By("passing more than 1 arguments", func() {
|
||||
helper.Cmd("odo", "create", "nodejs", "mynode").ShouldFail()
|
||||
|
||||
})
|
||||
By("invalid value to the --devfile flag", func() {
|
||||
helper.Cmd("odo", "create", "nodejs", "--devfile", "/path/to/file").ShouldFail()
|
||||
})
|
||||
|
||||
By("creating the devfile component multiple times", func() {
|
||||
helper.Cmd("odo", "create", "nodejs").ShouldPass()
|
||||
output := helper.Cmd("odo", "create", "nodejs").ShouldFail().Err()
|
||||
Expect(output).To(ContainSubstring("this directory already contains a component"))
|
||||
})
|
||||
})
|
||||
When("devfile contains parent URI", func() {
|
||||
var originalKeyList []string
|
||||
var content map[string]interface{}
|
||||
BeforeEach(func() {
|
||||
var err error
|
||||
devfilePath = filepath.Join(commonVar.Context, devfile)
|
||||
helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile-with-parent.yaml"), devfilePath)
|
||||
originalDevfileContent, err := ioutil.ReadFile(devfilePath)
|
||||
Expect(err).To(BeNil())
|
||||
Expect(yaml.Unmarshal(originalDevfileContent, &content)).To(BeNil())
|
||||
for k := range content {
|
||||
originalKeyList = append(originalKeyList, k)
|
||||
}
|
||||
})
|
||||
It("should not replace the original devfile", func() {
|
||||
helper.Cmd("odo", "create").ShouldPass()
|
||||
devfileContent, err := ioutil.ReadFile(devfilePath)
|
||||
Expect(err).To(BeNil())
|
||||
Expect(yaml.Unmarshal(devfileContent, &content)).To(BeNil())
|
||||
for k := range content {
|
||||
Expect(k).To(BeElementOf(originalKeyList))
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
When("devfile does not exist in the working directory and user specifies the devfile path via --devfile", func() {
|
||||
BeforeEach(func() {
|
||||
newContext := path.Join(commonVar.Context, "newContext")
|
||||
devfilePath = filepath.Join(newContext, devfile)
|
||||
helper.MakeDir(newContext)
|
||||
helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", devfile), devfilePath)
|
||||
})
|
||||
|
||||
It("should successfully create the devfile component with valid file system path", func() {
|
||||
helper.Cmd("odo", "create", "nodejs", "--devfile", devfilePath).ShouldPass()
|
||||
})
|
||||
|
||||
It("should successfully create the devfile component with valid specifies URL path", func() {
|
||||
helper.Cmd("odo", "create", "nodejs", "--devfile", "https://raw.githubusercontent.com/odo-devfiles/registry/master/devfiles/nodejs/devfile.yaml").ShouldPass()
|
||||
})
|
||||
|
||||
It("should fail to create the devfile component", func() {
|
||||
By("using an invalid file system path", func() {
|
||||
errOut := helper.Cmd("odo", "create", "nodejs", "--devfile", "@123!").ShouldFail().Err()
|
||||
Expect(errOut).To(ContainSubstring("the devfile path you specify is invalid"))
|
||||
})
|
||||
By("using an invalid URL path", func() {
|
||||
errOut := helper.Cmd("odo", "create", "nodejs", "--devfile", "://www.example.com/").ShouldFail().Err()
|
||||
Expect(errOut).To(ContainSubstring("the devfile path you specify is invalid"))
|
||||
})
|
||||
|
||||
By("passing more than 1 arguments", func() {
|
||||
errOut := helper.Cmd("odo", "create", "nodejs", "nodejs", "--devfile", devfilePath).ShouldFail().Err()
|
||||
Expect(errOut).To(ContainSubstring("accepts between 0 and 1 arg when using existing devfile, received 2"))
|
||||
})
|
||||
|
||||
By("using --registry flag", func() {
|
||||
errOut := helper.Cmd("odo", "create", "nodejs", "--devfile", devfilePath, "--registry", "DefaultDevfileRegistry").ShouldFail().Err()
|
||||
Expect(errOut).To(ContainSubstring("you can't specify registry via --registry if you want to use the devfile that is specified via --devfile"))
|
||||
})
|
||||
})
|
||||
When("devfile contains parent URI", func() {
|
||||
var originalKeyList []string
|
||||
var content map[string]interface{}
|
||||
BeforeEach(func() {
|
||||
var err error
|
||||
helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile-with-parent.yaml"), devfilePath)
|
||||
originalDevfileContent, err := ioutil.ReadFile(devfilePath)
|
||||
Expect(err).To(BeNil())
|
||||
err = yaml.Unmarshal(originalDevfileContent, &content)
|
||||
Expect(err).To(BeNil())
|
||||
for k := range content {
|
||||
originalKeyList = append(originalKeyList, k)
|
||||
}
|
||||
})
|
||||
It("should not replace the original devfile", func() {
|
||||
helper.Cmd("odo", "create", "mycomp", "--devfile", devfilePath).ShouldPass()
|
||||
devfileContent, err := ioutil.ReadFile(filepath.Join(commonVar.Context, devfile))
|
||||
Expect(err).To(BeNil())
|
||||
var content map[string]interface{}
|
||||
err = yaml.Unmarshal(devfileContent, &content)
|
||||
Expect(err).To(BeNil())
|
||||
for k := range content {
|
||||
Expect(k).To(BeElementOf(originalKeyList))
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
When("a dangling env file exists in the working directory", func() {
|
||||
BeforeEach(func() {
|
||||
helper.Cmd("odo", "create", "java-quarkus").ShouldPass()
|
||||
helper.DeleteFile("devfile.yaml")
|
||||
})
|
||||
It("should successfully create a devfile component and remove the dangling env file", func() {
|
||||
out, outerr := helper.Cmd("odo", "create", "nodejs").ShouldPass().OutAndErr()
|
||||
helper.MatchAllInOutput(out, []string{
|
||||
"Please use `odo push` command to create the component with source deployed"})
|
||||
helper.MatchAllInOutput(outerr, []string{
|
||||
"Found a dangling env file without a devfile, overwriting it",
|
||||
})
|
||||
})
|
||||
})
|
||||
When("creating a component using .devfile.yaml", func() {
|
||||
var stdout string
|
||||
BeforeEach(func() {
|
||||
helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile.yaml"), filepath.Join(commonVar.Context, ".devfile.yaml"))
|
||||
stdout = helper.Cmd("odo", "create", cmpName, "--project", commonVar.Project).ShouldPass().Out()
|
||||
})
|
||||
|
||||
It("should successfully create a devfile component", func() {
|
||||
Expect(stdout).To(ContainSubstring("Please use `odo push` command to create the component with source deployed"))
|
||||
})
|
||||
})
|
||||
|
||||
When("there is already a devfile in the directory", func() {
|
||||
BeforeEach(func() {
|
||||
helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile.yaml"), filepath.Join(commonVar.Context, "devfile.yaml"))
|
||||
})
|
||||
It("should fail with appropriate error when --starter is given to odo create", func() {
|
||||
stderr := helper.Cmd("odo", "create", "--starter", "nodejs-starter", "--context", commonVar.Context, "--project", commonVar.Project).ShouldFail().Err()
|
||||
Expect(stderr).To(ContainSubstring("already has a devfile so you cannot provide a starter"))
|
||||
})
|
||||
})
|
||||
|
||||
When("a devfile is provided which has a starter that has its own devfile", func() {
|
||||
BeforeEach(func() {
|
||||
examplesPath := helper.GetExamplePath()
|
||||
helper.Cmd("odo", "create", "nodejs", "--project", commonVar.Project, "--context", commonVar.Context, "--starter", "nodejs-starter", "--devfile", filepath.Join(examplesPath, "source", "devfiles", "nodejs", "devfile-with-starter-with-devfile.yaml")).ShouldPass()
|
||||
})
|
||||
It("should pass and keep the devfile in starter", func() {
|
||||
devfileContent, err := helper.ReadFile(filepath.Join(commonVar.Context, "devfile.yaml"))
|
||||
Expect(err).To(Not(HaveOccurred()))
|
||||
helper.MatchAllInOutput(devfileContent, []string{"2.2.0", "outerloop-deploy", "deployk8s", "outerloop-build"})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,14 +1,16 @@
|
||||
package devfile
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/redhat-developer/odo/tests/helper"
|
||||
"gopkg.in/yaml.v2"
|
||||
|
||||
"github.com/redhat-developer/odo/tests/helper"
|
||||
)
|
||||
|
||||
var _ = Describe("odo devfile init command tests", func() {
|
||||
@@ -35,6 +37,9 @@ var _ = Describe("odo devfile init command tests", func() {
|
||||
files := helper.ListFilesInDir(commonVar.Context)
|
||||
Expect(len(files)).To(Equal(0))
|
||||
})
|
||||
By("using an invalid devfile name", func() {
|
||||
helper.Cmd("odo", "init", "--name", "aname", "--devfile", "invalid").ShouldFail()
|
||||
})
|
||||
By("running odo init in a directory containing a devfile.yaml", func() {
|
||||
helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile-registry.yaml"), filepath.Join(commonVar.Context, "devfile.yaml"))
|
||||
defer os.Remove(filepath.Join(commonVar.Context, "devfile.yaml"))
|
||||
@@ -44,7 +49,7 @@ var _ = Describe("odo devfile init command tests", func() {
|
||||
|
||||
By("running odo init in a directory containing a .devfile.yaml", func() {
|
||||
helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile-registry.yaml"), filepath.Join(commonVar.Context, ".devfile.yaml"))
|
||||
defer os.Remove(filepath.Join(commonVar.Context, ".devfile.yaml"))
|
||||
defer helper.DeleteFile(filepath.Join(commonVar.Context, ".devfile.yaml"))
|
||||
err := helper.Cmd("odo", "init").ShouldFail().Err()
|
||||
Expect(err).To(ContainSubstring("a devfile already exists in the current directory"))
|
||||
})
|
||||
@@ -57,17 +62,36 @@ var _ = Describe("odo devfile init command tests", func() {
|
||||
err := helper.Cmd("odo", "init", "--name", "aname", "--devfile-path", "https://github.com/path/to/devfile.yaml").ShouldFail().Err()
|
||||
Expect(err).To(ContainSubstring("unable to download devfile"))
|
||||
})
|
||||
By("running odo init multiple times", func() {
|
||||
helper.Cmd("odo", "init", "--name", "aname", "--devfile", "nodejs").ShouldPass()
|
||||
defer helper.DeleteFile(filepath.Join(commonVar.Context, "devfile.yaml"))
|
||||
output := helper.Cmd("odo", "init", "--name", "aname", "--devfile", "nodejs").ShouldFail().Err()
|
||||
Expect(output).To(ContainSubstring("a devfile already exists in the current directory"))
|
||||
})
|
||||
|
||||
By("running odo init with --devfile-path and --devfile-registry", func() {
|
||||
errOut := helper.Cmd("odo", "init", "--name", "aname", "--devfile-path", "https://github.com/path/to/devfile.yaml", "--devfile-registry", "DefaultDevfileRegistry").ShouldFail().Err()
|
||||
Expect(errOut).To(ContainSubstring("--devfile-registry parameter cannot be used with --devfile-path"))
|
||||
})
|
||||
By("running odo init with invalid --devfile-registry value", func() {
|
||||
fakeRegistry := "fake"
|
||||
errOut := helper.Cmd("odo", "init", "--name", "aname", "--devfile-path", "https://github.com/path/to/devfile.yaml", "--devfile-registry", fakeRegistry).ShouldFail().Err()
|
||||
Expect(errOut).To(ContainSubstring(fmt.Sprintf("%q not found", fakeRegistry)))
|
||||
})
|
||||
})
|
||||
|
||||
Context("running odo init with valid flags", func() {
|
||||
When("using --devfile flag", func() {
|
||||
compName := "aname"
|
||||
BeforeEach(func() {
|
||||
helper.Cmd("odo", "init", "--name", "aname", "--devfile", "go").ShouldPass().Out()
|
||||
helper.Cmd("odo", "init", "--name", compName, "--devfile", "go").ShouldPass().Out()
|
||||
})
|
||||
|
||||
It("should download a devfile.yaml file", func() {
|
||||
It("should download a devfile.yaml file and correctly set the component name in it", func() {
|
||||
files := helper.ListFilesInDir(commonVar.Context)
|
||||
Expect(files).To(Equal([]string{"devfile.yaml"}))
|
||||
metadata := helper.GetMetadataFromDevfile(filepath.Join(commonVar.Context, "devfile.yaml"))
|
||||
Expect(metadata.Name).To(BeEquivalentTo(compName))
|
||||
})
|
||||
})
|
||||
When("using --devfile-path flag with a local devfile", func() {
|
||||
@@ -95,9 +119,81 @@ var _ = Describe("odo devfile init command tests", func() {
|
||||
Expect(files).To(Equal([]string{"devfile.yaml"}))
|
||||
})
|
||||
})
|
||||
|
||||
When("using --devfile-registry flag", func() {
|
||||
It("should successfully run odo init if specified registry is valid", func() {
|
||||
helper.Cmd("odo", "init", "--name", "aname", "--devfile", "go", "--devfile-registry", "DefaultDevfileRegistry").ShouldPass()
|
||||
})
|
||||
|
||||
})
|
||||
})
|
||||
When("a dangling env file exists in the working directory", func() {
|
||||
BeforeEach(func() {
|
||||
helper.CreateLocalEnv(commonVar.Context, "aname", commonVar.Project)
|
||||
})
|
||||
It("should successfully create a devfile component and remove the dangling env file", func() {
|
||||
helper.Cmd("odo", "init", "--name", "aname", "--devfile", "go").ShouldPass()
|
||||
})
|
||||
})
|
||||
|
||||
When("a devfile is provided which has a starter that has its own devfile", func() {
|
||||
BeforeEach(func() {
|
||||
helper.Cmd("odo", "init", "--name", "aname", "--starter", "nodejs-starter", "--devfile-path", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile-with-starter-with-devfile.yaml")).ShouldPass()
|
||||
})
|
||||
It("should pass and keep the devfile in starter", func() {
|
||||
devfileContent, err := helper.ReadFile(filepath.Join(commonVar.Context, "devfile.yaml"))
|
||||
Expect(err).To(Not(HaveOccurred()))
|
||||
helper.MatchAllInOutput(devfileContent, []string{"2.2.0", "outerloop-deploy", "deployk8s", "outerloop-build"})
|
||||
})
|
||||
})
|
||||
|
||||
When("running odo init with a devfile that has a subDir starter project", func() {
|
||||
BeforeEach(func() {
|
||||
helper.Cmd("odo", "init", "--name", "aname", "--devfile-path", helper.GetExamplePath("source", "devfiles", "springboot", "devfile-with-subDir.yaml"), "--starter", "springbootproject").ShouldPass()
|
||||
})
|
||||
|
||||
It("should successfully extract the project in the specified subDir path", func() {
|
||||
var found, notToBeFound int
|
||||
pathsToValidate := map[string]bool{
|
||||
filepath.Join(commonVar.Context, "java", "com"): true,
|
||||
filepath.Join(commonVar.Context, "java", "com", "example"): true,
|
||||
filepath.Join(commonVar.Context, "java", "com", "example", "demo"): true,
|
||||
filepath.Join(commonVar.Context, "java", "com", "example", "demo", "DemoApplication.java"): true,
|
||||
filepath.Join(commonVar.Context, "resources", "application.properties"): true,
|
||||
}
|
||||
pathsNotToBePresent := map[string]bool{
|
||||
filepath.Join(commonVar.Context, "src"): true,
|
||||
filepath.Join(commonVar.Context, "main"): true,
|
||||
}
|
||||
err := filepath.Walk(commonVar.Context, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if ok := pathsToValidate[path]; ok {
|
||||
found++
|
||||
}
|
||||
if ok := pathsNotToBePresent[path]; ok {
|
||||
notToBeFound++
|
||||
}
|
||||
return nil
|
||||
})
|
||||
Expect(err).To(BeNil())
|
||||
|
||||
Expect(found).To(Equal(len(pathsToValidate)))
|
||||
Expect(notToBeFound).To(Equal(0))
|
||||
})
|
||||
})
|
||||
|
||||
It("should successfully run odo init for devfile with starter project from the specified branch", func() {
|
||||
helper.Cmd("odo", "init", "--name", "aname", "--devfile-path", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile-with-branch.yaml"), "--starter", "nodejs-starter").ShouldPass()
|
||||
expectedFiles := []string{"package.json", "package-lock.json", "README.md", "devfile.yaml", "test"}
|
||||
Expect(helper.ListFilesInDir(commonVar.Context)).To(ContainElements(expectedFiles))
|
||||
})
|
||||
|
||||
It("should successfully run odo init for devfile with starter project from the specified tag", func() {
|
||||
helper.Cmd("odo", "init", "--name", "aname", "--devfile-path", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile-with-tag.yaml"), "--starter", "nodejs-starter").ShouldPass()
|
||||
expectedFiles := []string{"package.json", "package-lock.json", "README.md", "devfile.yaml", "app"}
|
||||
Expect(helper.ListFilesInDir(commonVar.Context)).To(ContainElements(expectedFiles))
|
||||
})
|
||||
When("running odo init from a directory with sources", func() {
|
||||
BeforeEach(func() {
|
||||
helper.CopyExample(filepath.Join("source", "nodejs"), commonVar.Context)
|
||||
|
||||
@@ -5,9 +5,10 @@ import (
|
||||
"path/filepath"
|
||||
|
||||
devfilepkg "github.com/devfile/api/v2/pkg/devfile"
|
||||
"github.com/tidwall/gjson"
|
||||
|
||||
"github.com/redhat-developer/odo/pkg/component"
|
||||
"github.com/redhat-developer/odo/tests/helper"
|
||||
"github.com/tidwall/gjson"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
@@ -32,9 +33,9 @@ var _ = Describe("odo list with devfile", func() {
|
||||
When("a component created in 'app' application", func() {
|
||||
|
||||
BeforeEach(func() {
|
||||
helper.Cmd("odo", "create", "--project", commonVar.Project, cmpName, "--devfile", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile.yaml")).ShouldPass()
|
||||
helper.Cmd("odo", "init", "--name", cmpName, "--devfile-path", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile.yaml")).ShouldPass()
|
||||
helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), commonVar.Context)
|
||||
|
||||
helper.CreateLocalEnv(commonVar.Context, cmpName, commonVar.Project)
|
||||
})
|
||||
|
||||
It("should show the component as 'Not Pushed'", func() {
|
||||
@@ -52,7 +53,9 @@ var _ = Describe("odo list with devfile", func() {
|
||||
Context("devfile has missing metadata", func() {
|
||||
// Note: We will be using SpringBoot example here because it helps to distinguish between language and projectType.
|
||||
// In terms of SpringBoot, spring is the projectType and java is the language; see https://github.com/redhat-developer/odo/issues/4815
|
||||
|
||||
BeforeEach(func() {
|
||||
helper.CopyExample(filepath.Join("source", "devfiles", "springboot", "project"), commonVar.Context)
|
||||
})
|
||||
var metadata devfilepkg.DevfileMetadata
|
||||
|
||||
// checkList checks the list output (both normal and json) to see if it contains the expected componentType
|
||||
@@ -69,7 +72,8 @@ var _ = Describe("odo list with devfile", func() {
|
||||
|
||||
When("projectType is missing", func() {
|
||||
BeforeEach(func() {
|
||||
helper.CopyAndCreate(filepath.Join("source", "devfiles", "springboot", "project"), filepath.Join("source", "devfiles", "springboot", "devfile-with-missing-projectType-metadata.yaml"), commonVar.Context)
|
||||
helper.Cmd("odo", "init", "--name", "aname", "--devfile-path", helper.GetExamplePath("source", "devfiles", "springboot", "devfile-with-missing-projectType-metadata.yaml")).ShouldPass()
|
||||
helper.CreateLocalEnv(commonVar.Context, "aname", commonVar.Project)
|
||||
metadata = helper.GetMetadataFromDevfile(filepath.Join(commonVar.Context, "devfile.yaml"))
|
||||
})
|
||||
|
||||
@@ -93,7 +97,8 @@ var _ = Describe("odo list with devfile", func() {
|
||||
|
||||
When("projectType and language is missing", func() {
|
||||
BeforeEach(func() {
|
||||
helper.CopyAndCreate(filepath.Join("source", "devfiles", "springboot", "project"), filepath.Join("source", "devfiles", "springboot", "devfile-with-missing-projectType-and-language-metadata.yaml"), commonVar.Context)
|
||||
helper.Cmd("odo", "init", "--name", "aname", "--devfile-path", helper.GetExamplePath("source", "devfiles", "springboot", "devfile-with-missing-projectType-and-language-metadata.yaml")).ShouldPass()
|
||||
helper.CreateLocalEnv(commonVar.Context, "aname", commonVar.Project)
|
||||
metadata = helper.GetMetadataFromDevfile(filepath.Join(commonVar.Context, "devfile.yaml"))
|
||||
})
|
||||
It("should show 'Not available' for 'Type' in odo list", func() {
|
||||
|
||||
@@ -1,931 +0,0 @@
|
||||
package devfile
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/redhat-developer/odo/pkg/util"
|
||||
"github.com/redhat-developer/odo/tests/helper"
|
||||
"github.com/redhat-developer/odo/tests/integration/devfile/utils"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("odo devfile push command tests", func() {
|
||||
var cmpName string
|
||||
var sourcePath = "/projects"
|
||||
var commonVar helper.CommonVar
|
||||
|
||||
// This is run before every Spec (It)
|
||||
var _ = BeforeEach(func() {
|
||||
commonVar = helper.CommonBeforeEach()
|
||||
cmpName = helper.RandString(6)
|
||||
helper.Chdir(commonVar.Context)
|
||||
})
|
||||
|
||||
// This is run after every Spec (It)
|
||||
var _ = AfterEach(func() {
|
||||
helper.CommonAfterEach(commonVar)
|
||||
})
|
||||
|
||||
When("creating a nodejs component", func() {
|
||||
output := ""
|
||||
BeforeEach(func() {
|
||||
helper.Cmd("odo", "create", "--project", commonVar.Project, cmpName, "--devfile", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile-registry.yaml")).ShouldPass()
|
||||
helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), commonVar.Context)
|
||||
})
|
||||
When("setting git config and running odo push", func() {
|
||||
remoteURL := "https://github.com/odo-devfiles/nodejs-ex"
|
||||
BeforeEach(func() {
|
||||
helper.Cmd("git", "init").ShouldPass()
|
||||
remote := "origin"
|
||||
helper.Cmd("git", "remote", "add", remote, remoteURL).ShouldPass()
|
||||
helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile.yaml"), filepath.Join(commonVar.Context, "devfile.yaml"))
|
||||
output = helper.Cmd("odo", "push", "--project", commonVar.Project).ShouldPass().Out()
|
||||
})
|
||||
|
||||
It("checks that odo push works with a devfile", func() {
|
||||
Expect(output).To(ContainSubstring("Changes successfully pushed to component"))
|
||||
})
|
||||
|
||||
It("check annotations from the deployment after odo push", func() {
|
||||
|
||||
annotations := commonVar.CliRunner.GetAnnotationsDeployment(cmpName, "app", commonVar.Project)
|
||||
var valueFound bool
|
||||
for key, value := range annotations {
|
||||
if key == "app.openshift.io/vcs-uri" && value == remoteURL {
|
||||
valueFound = true
|
||||
}
|
||||
}
|
||||
Expect(valueFound).To(BeTrue())
|
||||
})
|
||||
|
||||
When("updating a variable into devfile", func() {
|
||||
BeforeEach(func() {
|
||||
helper.ReplaceString("devfile.yaml", "name: FOO", "name: BAR")
|
||||
})
|
||||
|
||||
It("should run odo push successfully", func() {
|
||||
helper.Cmd("odo", "push", "--project", commonVar.Project).ShouldPass()
|
||||
})
|
||||
|
||||
})
|
||||
})
|
||||
|
||||
When("odo push is executed with json output", func() {
|
||||
|
||||
BeforeEach(func() {
|
||||
helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile.yaml"), filepath.Join(commonVar.Context, "devfile.yaml"))
|
||||
output = helper.Cmd("odo", "push", "-o", "json", "--project", commonVar.Project).ShouldPass().Out()
|
||||
})
|
||||
|
||||
It("should display push output in JSON format", func() {
|
||||
|
||||
utils.AnalyzePushConsoleOutput(output)
|
||||
})
|
||||
When("update devfile and push again", func() {
|
||||
|
||||
BeforeEach(func() {
|
||||
helper.ReplaceString("devfile.yaml", "name: FOO", "name: BAR")
|
||||
output = helper.Cmd("odo", "push", "-o", "json", "--project", commonVar.Project).ShouldPass().Out()
|
||||
})
|
||||
|
||||
It("should display push updated output in JSON format", func() {
|
||||
|
||||
utils.AnalyzePushConsoleOutput(output)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
When("running odo push outside the context directory", func() {
|
||||
newContext := ""
|
||||
BeforeEach(func() {
|
||||
newContext = helper.CreateNewContext()
|
||||
helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile.yaml"), filepath.Join(commonVar.Context, "devfile.yaml"))
|
||||
|
||||
helper.Chdir(newContext)
|
||||
output = helper.Cmd("odo", "push", "--context", commonVar.Context).ShouldPass().Out()
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
helper.Chdir(commonVar.Context)
|
||||
helper.DeleteDir(newContext)
|
||||
})
|
||||
|
||||
It("should push correct component based on --context flag", func() {
|
||||
|
||||
Expect(output).To(ContainSubstring("Changes successfully pushed to component"))
|
||||
})
|
||||
})
|
||||
|
||||
When("Devfile 2.1.0 is used", func() {
|
||||
|
||||
BeforeEach(func() {
|
||||
helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile-variables.yaml"), filepath.Join(commonVar.Context, "devfile.yaml"))
|
||||
})
|
||||
|
||||
When("doing odo push", func() {
|
||||
|
||||
BeforeEach(func() {
|
||||
output = helper.Cmd("odo", "push").ShouldPass().Out()
|
||||
})
|
||||
|
||||
It("should pass", func() {
|
||||
|
||||
Expect(output).To(ContainSubstring("Changes successfully pushed to component"))
|
||||
})
|
||||
It("should check if the env variable has a correct value", func() {
|
||||
|
||||
envVars := commonVar.CliRunner.GetEnvsDevFileDeployment(cmpName, "app", commonVar.Project)
|
||||
// check if the env variable has a correct value. This value was substituted from in devfile from variable
|
||||
Expect(envVars["FOO"]).To(Equal("bar"))
|
||||
})
|
||||
})
|
||||
})
|
||||
When("doing odo push", func() {
|
||||
BeforeEach(func() {
|
||||
helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile.yaml"), filepath.Join(commonVar.Context, "devfile.yaml"))
|
||||
helper.Cmd("odo", "push", "--project", commonVar.Project).ShouldPass()
|
||||
})
|
||||
When("doing odo push with -f flag", func() {
|
||||
BeforeEach(func() {
|
||||
output = helper.Cmd("odo", "push", "-f", "--project", commonVar.Project).ShouldPass().Out()
|
||||
})
|
||||
It("should build even when no changes are detected", func() {
|
||||
Expect(output).To(Not(ContainSubstring("No file changes detected, skipping build")))
|
||||
})
|
||||
})
|
||||
|
||||
When("the pod is deleted and replaced", func() {
|
||||
BeforeEach(func() {
|
||||
oldPod := commonVar.CliRunner.GetRunningPodNameByComponent(cmpName, commonVar.Project)
|
||||
commonVar.CliRunner.DeletePod(oldPod, commonVar.Project)
|
||||
Eventually(func() bool {
|
||||
newPod := commonVar.CliRunner.GetRunningPodNameByComponent(cmpName, commonVar.Project)
|
||||
return newPod != "" && newPod != oldPod
|
||||
}, 180, 10).Should(Equal(true))
|
||||
newPod := commonVar.CliRunner.GetRunningPodNameByComponent(cmpName, commonVar.Project)
|
||||
commonVar.CliRunner.PodsShouldBeRunning(commonVar.Project, newPod)
|
||||
})
|
||||
|
||||
It("should execute run command on odo push", func() {
|
||||
output = helper.Cmd("odo", "push", "--project", commonVar.Project).ShouldPass().Out()
|
||||
})
|
||||
})
|
||||
|
||||
When("the Deployment's Replica count (pods) is scaled to 0", func() {
|
||||
BeforeEach(func() {
|
||||
commonVar.CliRunner.ScalePodToZero(cmpName, "app", commonVar.Project)
|
||||
})
|
||||
|
||||
It("odo push should successfully recreate the pod", func() {
|
||||
helper.Cmd("odo", "push").ShouldPass()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
When("creating local files and dir and doing odo push", func() {
|
||||
var newDirPath, newFilePath, stdOut, podName string
|
||||
BeforeEach(func() {
|
||||
newFilePath = filepath.Join(commonVar.Context, "foobar.txt")
|
||||
newDirPath = filepath.Join(commonVar.Context, "testdir")
|
||||
helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile.yaml"), filepath.Join(commonVar.Context, "devfile.yaml"))
|
||||
// Create a new file that we plan on deleting later...
|
||||
if err := helper.CreateFileWithContent(newFilePath, "hello world"); err != nil {
|
||||
fmt.Printf("the foobar.txt file was not created, reason %v", err.Error())
|
||||
}
|
||||
// Create a new directory
|
||||
helper.MakeDir(newDirPath)
|
||||
helper.Cmd("odo", "push", "--project", commonVar.Project, "-v4").ShouldPass()
|
||||
})
|
||||
|
||||
It("should correctly propagate changes to the container", func() {
|
||||
|
||||
// Check to see if it's been pushed (foobar.txt abd directory testdir)
|
||||
podName = commonVar.CliRunner.GetRunningPodNameByComponent(cmpName, commonVar.Project)
|
||||
|
||||
stdOut = commonVar.CliRunner.ExecListDir(podName, commonVar.Project, sourcePath)
|
||||
helper.MatchAllInOutput(stdOut, []string{"foobar.txt", "testdir"})
|
||||
})
|
||||
When("deleting local files and dir and doing odo push again", func() {
|
||||
BeforeEach(func() {
|
||||
// Now we delete the file and dir and push
|
||||
helper.DeleteDir(newFilePath)
|
||||
helper.DeleteDir(newDirPath)
|
||||
helper.Cmd("odo", "push", "--project", commonVar.Project, "-v4").ShouldPass()
|
||||
})
|
||||
It("should not list deleted dir and file in container", func() {
|
||||
podName = commonVar.CliRunner.GetRunningPodNameByComponent(cmpName, commonVar.Project)
|
||||
// Then check to see if it's truly been deleted
|
||||
stdOut = commonVar.CliRunner.ExecListDir(podName, commonVar.Project, sourcePath)
|
||||
helper.DontMatchAllInOutput(stdOut, []string{"foobar.txt", "testdir"})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
When("devfile has sourcemappings and doing odo push", func() {
|
||||
BeforeEach(func() {
|
||||
helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfileSourceMapping.yaml"), filepath.Join(commonVar.Context, "devfile.yaml"))
|
||||
helper.Cmd("odo", "push", "--project", commonVar.Project).ShouldPass().Out()
|
||||
})
|
||||
It("should sync files to the correct location", func() {
|
||||
|
||||
// Verify source code was synced to /test instead of /projects
|
||||
var statErr error
|
||||
podName := commonVar.CliRunner.GetRunningPodNameByComponent(cmpName, commonVar.Project)
|
||||
commonVar.CliRunner.CheckCmdOpInRemoteDevfilePod(
|
||||
podName,
|
||||
"runtime",
|
||||
commonVar.Project,
|
||||
[]string{"stat", "/test/server.js"},
|
||||
func(cmdOp string, err error) bool {
|
||||
statErr = err
|
||||
return err == nil
|
||||
},
|
||||
)
|
||||
Expect(statErr).ToNot(HaveOccurred())
|
||||
})
|
||||
})
|
||||
|
||||
When("project and clonePath is present in devfile and doing odo push", func() {
|
||||
BeforeEach(func() {
|
||||
// devfile with clonePath set in project field
|
||||
helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile-with-projects.yaml"), filepath.Join(commonVar.Context, "devfile.yaml"))
|
||||
|
||||
helper.Cmd("odo", "push", "--v", "5").ShouldPass()
|
||||
})
|
||||
|
||||
It("should sync to the correct dir in container", func() {
|
||||
podName := commonVar.CliRunner.GetRunningPodNameByComponent(cmpName, commonVar.Project)
|
||||
// source code is synced to $PROJECTS_ROOT/clonePath
|
||||
// $PROJECTS_ROOT is /projects by default, if sourceMapping is set it is same as sourceMapping
|
||||
// for devfile-with-projects.yaml, sourceMapping is apps and clonePath is webapp
|
||||
// so source code would be synced to /apps/webapp
|
||||
output = commonVar.CliRunner.ExecListDir(podName, commonVar.Project, "/apps/webapp")
|
||||
helper.MatchAllInOutput(output, []string{"package.json"})
|
||||
|
||||
// Verify the sync env variables are correct
|
||||
utils.VerifyContainerSyncEnv(podName, "runtime", commonVar.Project, "/apps/webapp", "/apps", commonVar.CliRunner)
|
||||
})
|
||||
})
|
||||
|
||||
When("devfile project field is present and doing odo push", func() {
|
||||
BeforeEach(func() {
|
||||
helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile-with-projects.yaml"), filepath.Join(commonVar.Context, "devfile.yaml"))
|
||||
|
||||
// reset clonePath and change the workdir accordingly, it should sync to project name
|
||||
helper.ReplaceString(filepath.Join(commonVar.Context, "devfile.yaml"), "clonePath: webapp/", "# clonePath: webapp/")
|
||||
helper.Cmd("odo", "push").ShouldPass()
|
||||
})
|
||||
It("should sync to the correct dir in container", func() {
|
||||
podName := commonVar.CliRunner.GetRunningPodNameByComponent(cmpName, commonVar.Project)
|
||||
output = commonVar.CliRunner.ExecListDir(podName, commonVar.Project, "/apps/nodeshift")
|
||||
helper.MatchAllInOutput(output, []string{"package.json"})
|
||||
|
||||
// Verify the sync env variables are correct
|
||||
utils.VerifyContainerSyncEnv(podName, "runtime", commonVar.Project, "/apps/nodeshift", "/apps", commonVar.CliRunner)
|
||||
})
|
||||
})
|
||||
|
||||
When("multiple project is present", func() {
|
||||
BeforeEach(func() {
|
||||
helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile-with-multiple-projects.yaml"), filepath.Join(commonVar.Context, "devfile.yaml"))
|
||||
helper.Cmd("odo", "push").ShouldPass()
|
||||
})
|
||||
It("should sync to the correct dir in container", func() {
|
||||
|
||||
podName := commonVar.CliRunner.GetRunningPodNameByComponent(cmpName, commonVar.Project)
|
||||
// for devfile-with-multiple-projects.yaml source mapping is not set so $PROJECTS_ROOT is /projects
|
||||
// multiple projects, so source code would sync to the first project /projects/webapp
|
||||
output = commonVar.CliRunner.ExecListDir(podName, commonVar.Project, "/projects/webapp")
|
||||
helper.MatchAllInOutput(output, []string{"package.json"})
|
||||
|
||||
// Verify the sync env variables are correct
|
||||
utils.VerifyContainerSyncEnv(podName, "runtime", commonVar.Project, "/projects/webapp", "/projects", commonVar.CliRunner)
|
||||
})
|
||||
})
|
||||
|
||||
When("no project is present", func() {
|
||||
BeforeEach(func() {
|
||||
helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile.yaml"), filepath.Join(commonVar.Context, "devfile.yaml"))
|
||||
helper.Cmd("odo", "push").ShouldPass()
|
||||
})
|
||||
It("should sync to the correct dir in container", func() {
|
||||
|
||||
podName := commonVar.CliRunner.GetRunningPodNameByComponent(cmpName, commonVar.Project)
|
||||
output = commonVar.CliRunner.ExecListDir(podName, commonVar.Project, "/projects")
|
||||
helper.MatchAllInOutput(output, []string{"package.json"})
|
||||
|
||||
// Verify the sync env variables are correct
|
||||
utils.VerifyContainerSyncEnv(podName, "runtime", commonVar.Project, "/projects", "/projects", commonVar.CliRunner)
|
||||
})
|
||||
})
|
||||
|
||||
When("doing odo push with devfile contain volume", func() {
|
||||
var statErr error
|
||||
var cmdOutput string
|
||||
|
||||
BeforeEach(func() {
|
||||
helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile-with-volumes.yaml"), filepath.Join(commonVar.Context, "devfile.yaml"))
|
||||
output = helper.Cmd("odo", "push", "--project", commonVar.Project).ShouldPass().Out()
|
||||
})
|
||||
It("should create pvc and reuse if it shares the same devfile volume name", func() {
|
||||
// Check to see if it's been pushed (foobar.txt abd directory testdir)
|
||||
podName := commonVar.CliRunner.GetRunningPodNameByComponent(cmpName, commonVar.Project)
|
||||
|
||||
commonVar.CliRunner.CheckCmdOpInRemoteDevfilePod(
|
||||
podName,
|
||||
"runtime2",
|
||||
commonVar.Project,
|
||||
[]string{"cat", "/myvol/myfile.log"},
|
||||
func(cmdOp string, err error) bool {
|
||||
cmdOutput = cmdOp
|
||||
statErr = err
|
||||
return err == nil
|
||||
},
|
||||
)
|
||||
Expect(statErr).ToNot(HaveOccurred())
|
||||
Expect(cmdOutput).To(ContainSubstring("hello"))
|
||||
|
||||
commonVar.CliRunner.CheckCmdOpInRemoteDevfilePod(
|
||||
podName,
|
||||
"runtime2",
|
||||
commonVar.Project,
|
||||
[]string{"stat", "/data2"},
|
||||
func(cmdOp string, err error) bool {
|
||||
statErr = err
|
||||
return err == nil
|
||||
},
|
||||
)
|
||||
Expect(statErr).ToNot(HaveOccurred())
|
||||
})
|
||||
It("check the volume name and mount paths for the containers", func() {
|
||||
deploymentName, err := util.NamespaceKubernetesObject(cmpName, "app")
|
||||
Expect(err).To(BeNil())
|
||||
|
||||
volumesMatched := false
|
||||
|
||||
// check the volume name and mount paths for the containers
|
||||
volNamesAndPaths := commonVar.CliRunner.GetVolumeMountNamesandPathsFromContainer(deploymentName, "runtime", commonVar.Project)
|
||||
volNamesAndPathsArr := strings.Fields(volNamesAndPaths)
|
||||
for _, volNamesAndPath := range volNamesAndPathsArr {
|
||||
volNamesAndPathArr := strings.Split(volNamesAndPath, ":")
|
||||
|
||||
if strings.Contains(volNamesAndPathArr[0], "myvol") && volNamesAndPathArr[1] == "/data" {
|
||||
volumesMatched = true
|
||||
}
|
||||
}
|
||||
Expect(volumesMatched).To(Equal(true))
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
When("doing odo push with devfile containing volume-component", func() {
|
||||
BeforeEach(func() {
|
||||
helper.RenameFile("devfile.yaml", "devfile-old.yaml")
|
||||
helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile-with-volume-components.yaml"), filepath.Join(commonVar.Context, "devfile.yaml"))
|
||||
|
||||
output = helper.Cmd("odo", "push", "--project", commonVar.Project).ShouldPass().Out()
|
||||
})
|
||||
It("should successfully use the volume components in container components", func() {
|
||||
|
||||
// Verify the pvc size for firstvol
|
||||
storageSize := commonVar.CliRunner.GetPVCSize(cmpName, "firstvol", commonVar.Project)
|
||||
// should be the default size
|
||||
Expect(storageSize).To(ContainSubstring("1Gi"))
|
||||
|
||||
// Verify the pvc size for secondvol
|
||||
storageSize = commonVar.CliRunner.GetPVCSize(cmpName, "secondvol", commonVar.Project)
|
||||
// should be the specified size in the devfile volume component
|
||||
Expect(storageSize).To(ContainSubstring("3Gi"))
|
||||
})
|
||||
})
|
||||
|
||||
When("doing odo push and run command is not marked as hotReloadCapable", func() {
|
||||
BeforeEach(func() {
|
||||
helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile.yaml"), filepath.Join(commonVar.Context, "devfile.yaml"))
|
||||
output = helper.Cmd("odo", "push").ShouldPass().Out()
|
||||
})
|
||||
It("should restart the application", func() {
|
||||
// TODO: this is almost the same test as one below
|
||||
|
||||
helper.Cmd("odo", "push", "-f").ShouldPass()
|
||||
})
|
||||
})
|
||||
|
||||
When("doing odo push and run command is marked as hotReloadCapable:true", func() {
|
||||
BeforeEach(func() {
|
||||
helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile-with-hotReload.yaml"), filepath.Join(commonVar.Context, "devfile.yaml"))
|
||||
output = helper.Cmd("odo", "push").ShouldPass().Out()
|
||||
})
|
||||
|
||||
It("should not restart the application", func() {
|
||||
|
||||
helper.Cmd("odo", "push", "-f").ShouldPass()
|
||||
})
|
||||
|
||||
When("doing odo push --debug ", func() {
|
||||
stdOut := ""
|
||||
BeforeEach(func() {
|
||||
stdOut = helper.Cmd("odo", "push", "--debug", "--project", commonVar.Project).ShouldPass().Out()
|
||||
})
|
||||
It("should restart the application regardless of hotReloadCapable value", func() {
|
||||
|
||||
Expect(stdOut).To(Not(ContainSubstring("No file changes detected, skipping build")))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
When("doing odo push and devfile with composite command", func() {
|
||||
BeforeEach(func() {
|
||||
helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfileCompositeCommands.yaml"), filepath.Join(commonVar.Context, "devfile.yaml"))
|
||||
output = helper.Cmd("odo", "push").ShouldPass().Out()
|
||||
})
|
||||
It("should execute all commands in composite commmand", func() {
|
||||
// Verify the command executed successfully
|
||||
var statErr error
|
||||
podName := commonVar.CliRunner.GetRunningPodNameByComponent(cmpName, commonVar.Project)
|
||||
commonVar.CliRunner.CheckCmdOpInRemoteDevfilePod(
|
||||
podName,
|
||||
"runtime",
|
||||
commonVar.Project,
|
||||
[]string{"stat", "/projects/testfolder"},
|
||||
func(cmdOp string, err error) bool {
|
||||
statErr = err
|
||||
return err == nil
|
||||
},
|
||||
)
|
||||
Expect(statErr).ToNot(HaveOccurred())
|
||||
})
|
||||
})
|
||||
When("doing odo push and composite command is marked as paralell:true ", func() {
|
||||
BeforeEach(func() {
|
||||
helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfileCompositeCommandsParallel.yaml"), filepath.Join(commonVar.Context, "devfile.yaml"))
|
||||
output = helper.Cmd("odo", "push", "--build-command", "buildandmkdir").ShouldPass().Out()
|
||||
})
|
||||
It("should execute all commands in composite commmand", func() {
|
||||
|
||||
// Verify the command executed successfully
|
||||
var statErr error
|
||||
podName := commonVar.CliRunner.GetRunningPodNameByComponent(cmpName, commonVar.Project)
|
||||
commonVar.CliRunner.CheckCmdOpInRemoteDevfilePod(
|
||||
podName,
|
||||
"runtime",
|
||||
commonVar.Project,
|
||||
[]string{"stat", "/projects/testfolder"},
|
||||
func(cmdOp string, err error) bool {
|
||||
statErr = err
|
||||
return err == nil
|
||||
},
|
||||
)
|
||||
Expect(statErr).ToNot(HaveOccurred())
|
||||
})
|
||||
})
|
||||
|
||||
When("doing odo push and composite command are nested", func() {
|
||||
BeforeEach(func() {
|
||||
helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfileNestedCompCommands.yaml"), filepath.Join(commonVar.Context, "devfile.yaml"))
|
||||
helper.Cmd("odo", "push").ShouldPass()
|
||||
})
|
||||
It("should execute all commands in composite commmand", func() {
|
||||
// Verify the command executed successfully
|
||||
var statErr error
|
||||
podName := commonVar.CliRunner.GetRunningPodNameByComponent(cmpName, commonVar.Project)
|
||||
commonVar.CliRunner.CheckCmdOpInRemoteDevfilePod(
|
||||
podName,
|
||||
"runtime",
|
||||
commonVar.Project,
|
||||
[]string{"stat", "/projects/testfolder"},
|
||||
func(cmdOp string, err error) bool {
|
||||
statErr = err
|
||||
return err == nil
|
||||
},
|
||||
)
|
||||
Expect(statErr).ToNot(HaveOccurred())
|
||||
})
|
||||
})
|
||||
When("doing odo push and composite command is used as a run command", func() {
|
||||
BeforeEach(func() {
|
||||
helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfileCompositeRun.yaml"), filepath.Join(commonVar.Context, "devfile.yaml"))
|
||||
output = helper.Cmd("odo", "push").ShouldFail().Err()
|
||||
})
|
||||
It("should throw a validation error for composite run commands", func() {
|
||||
Expect(output).To(ContainSubstring("not supported currently"))
|
||||
})
|
||||
})
|
||||
|
||||
When("events are defined", func() {
|
||||
|
||||
It("should correctly execute PreStart commands", func() {
|
||||
// expectedInitContainers := []string{"tools-myprestart-1", "tools-myprestart-2", "runtime-secondprestart-3"}
|
||||
|
||||
helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile-with-preStart.yaml"), filepath.Join(commonVar.Context, "devfile.yaml"))
|
||||
|
||||
output = helper.Cmd("odo", "push", "--project", commonVar.Project).ShouldFail().Err()
|
||||
// This is expected to fail for now.
|
||||
// see https://github.com/redhat-developer/odo/issues/4187 for more info
|
||||
helper.MatchAllInOutput(output, []string{"myprestart should either map to an apply command or a composite command with apply commands\n"})
|
||||
|
||||
/*
|
||||
helper.MatchAllInOutput(output, []string{"PreStart commands have been added to the component"})
|
||||
|
||||
firstPushPodName := commonVar.CliRunner.GetRunningPodNameByComponent(cmpName, commonVar.Project)
|
||||
|
||||
firstPushInitContainers := commonVar.CliRunner.GetPodInitContainers(cmpName, commonVar.Project)
|
||||
// 3 preStart events + 1 supervisord init containers
|
||||
Expect(len(firstPushInitContainers)).To(Equal(4))
|
||||
helper.MatchAllInOutput(strings.Join(firstPushInitContainers, ","), expectedInitContainers)
|
||||
|
||||
// Need to force so build and run get triggered again with the component already created.
|
||||
output = helper.Cmd("odo", "push", "--project", commonVar.Project, "-f").ShouldPass().Out()
|
||||
helper.MatchAllInOutput(output, []string{"PreStart commands have been added to the component"})
|
||||
|
||||
secondPushPodName := commonVar.CliRunner.GetRunningPodNameByComponent(cmpName, commonVar.Project)
|
||||
|
||||
secondPushInitContainers := commonVar.CliRunner.GetPodInitContainers(cmpName, commonVar.Project)
|
||||
|
||||
Expect(len(secondPushInitContainers)).To(Equal(4))
|
||||
helper.MatchAllInOutput(strings.Join(secondPushInitContainers, ","), expectedInitContainers)
|
||||
|
||||
Expect(firstPushPodName).To(Equal(secondPushPodName))
|
||||
Expect(firstPushInitContainers).To(Equal(secondPushInitContainers))
|
||||
|
||||
var statErr error
|
||||
commonVar.CliRunner.CheckCmdOpInRemoteDevfilePod(
|
||||
firstPushPodName,
|
||||
"runtime",
|
||||
commonVar.Project,
|
||||
[]string{"cat", "/projects/test.txt"},
|
||||
func(cmdOp string, err error) bool {
|
||||
if err != nil {
|
||||
statErr = err
|
||||
} else if cmdOp == "" {
|
||||
statErr = fmt.Errorf("prestart event action error, expected: hello test2\nhello test2\nhello test\n, got empty string")
|
||||
} else {
|
||||
fileContents := strings.Split(cmdOp, "\n")
|
||||
if len(fileContents)-1 != 3 {
|
||||
statErr = fmt.Errorf("prestart event action count error, expected: 3 strings, got %d strings: %s", len(fileContents), strings.Join(fileContents, ","))
|
||||
} else if cmdOp != "hello test2\nhello test2\nhello test\n" {
|
||||
statErr = fmt.Errorf("prestart event action error, expected: hello test2\nhello test2\nhello test\n, got: %s", cmdOp)
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
},
|
||||
)
|
||||
Expect(statErr).ToNot(HaveOccurred())
|
||||
*/
|
||||
})
|
||||
|
||||
It("should correctly execute PostStart commands", func() {
|
||||
|
||||
helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile-with-valid-events.yaml"), filepath.Join(commonVar.Context, "devfile.yaml"))
|
||||
|
||||
helper.Cmd("odo", "push", "--project", commonVar.Project).ShouldPass()
|
||||
|
||||
// Need to force so build and run get triggered again with the component already created.
|
||||
helper.Cmd("odo", "push", "--project", commonVar.Project, "-f").ShouldPass()
|
||||
})
|
||||
})
|
||||
|
||||
When("doing odo push and using wrong custom commands (specified by flags)", func() {
|
||||
BeforeEach(func() {
|
||||
helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile.yaml"), filepath.Join(commonVar.Context, "devfile.yaml"))
|
||||
output = helper.Cmd("odo", "push", "--build-command", "buildgarbage").ShouldFail().Err()
|
||||
})
|
||||
It("should error out", func() {
|
||||
|
||||
Expect(output).NotTo(ContainSubstring("Executing buildgarbage command"))
|
||||
Expect(output).To(ContainSubstring("the command \"%v\" is not found in the devfile", "buildgarbage"))
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
When("command has no group kind and doing odo push", func() {
|
||||
BeforeEach(func() {
|
||||
helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile-with-no-group-kind.yaml"), filepath.Join(commonVar.Context, "devfile.yaml"))
|
||||
output = helper.Cmd("odo", "push", "--build-command", "devbuild", "--run-command", "devrun").ShouldPass().Out()
|
||||
})
|
||||
It("should execute commands with flags", func() {
|
||||
helper.MatchAllInOutput(output, []string{
|
||||
"Building your application in container on cluster",
|
||||
})
|
||||
|
||||
})
|
||||
})
|
||||
|
||||
When("doing odo push and run command throws an error", func() {
|
||||
BeforeEach(func() {
|
||||
helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile.yaml"), filepath.Join(commonVar.Context, "devfile.yaml"))
|
||||
helper.ReplaceString(filepath.Join(commonVar.Context, "devfile.yaml"), "npm start", "npm starts")
|
||||
_, output = helper.Cmd("odo", "push").ShouldPass().OutAndErr()
|
||||
})
|
||||
|
||||
It("should wait and error out with some log", func() {
|
||||
|
||||
helper.MatchAllInOutput(output, []string{
|
||||
"exited with error status within 1 sec",
|
||||
"Did you mean one of these?",
|
||||
})
|
||||
|
||||
_, output = helper.Cmd("odo", "push", "-f", "--run-command", "run").ShouldPass().OutAndErr()
|
||||
helper.MatchAllInOutput(output, []string{
|
||||
"exited with error status within 1 sec",
|
||||
"Did you mean one of these?",
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
When("commands specify have env variables", func() {
|
||||
BeforeEach(func() {
|
||||
helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile-with-command-envs.yaml"), filepath.Join(commonVar.Context, "devfile.yaml"))
|
||||
})
|
||||
When("doing odo push and sigle env var is set", func() {
|
||||
BeforeEach(func() {
|
||||
helper.Cmd("odo", "push", "--build-command", "buildwithenv", "--run-command", "singleenv").ShouldPass()
|
||||
})
|
||||
It("should be able to exec command", func() {
|
||||
podName := commonVar.CliRunner.GetRunningPodNameByComponent(cmpName, commonVar.Project)
|
||||
output = commonVar.CliRunner.ExecListDir(podName, commonVar.Project, sourcePath)
|
||||
helper.MatchAllInOutput(output, []string{"test_env_variable", "test_build_env_variable"})
|
||||
})
|
||||
})
|
||||
When("doing odo push and multiple env variables are set", func() {
|
||||
BeforeEach(func() {
|
||||
output = helper.Cmd("odo", "push", "--build-command", "buildwithmultipleenv", "--run-command", "multipleenv").ShouldPass().Out()
|
||||
})
|
||||
It("should be able to exec command", func() {
|
||||
podName := commonVar.CliRunner.GetRunningPodNameByComponent(cmpName, commonVar.Project)
|
||||
output = commonVar.CliRunner.ExecListDir(podName, commonVar.Project, sourcePath)
|
||||
helper.MatchAllInOutput(output, []string{"test_build_env_variable1", "test_build_env_variable2", "test_env_variable1", "test_env_variable2"})
|
||||
})
|
||||
})
|
||||
When("doing odo push and there is a env variable with spaces", func() {
|
||||
BeforeEach(func() {
|
||||
helper.Cmd("odo", "push", "--build-command", "buildenvwithspace", "--run-command", "envwithspace").ShouldPass()
|
||||
})
|
||||
It("should be able to exec command", func() {
|
||||
podName := commonVar.CliRunner.GetRunningPodNameByComponent(cmpName, commonVar.Project)
|
||||
output = commonVar.CliRunner.ExecListDir(podName, commonVar.Project, sourcePath)
|
||||
helper.MatchAllInOutput(output, []string{"build env variable with space", "env with space"})
|
||||
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Context("pushing devfile without an .odo folder", func() {
|
||||
It("should error out on odo push and passing invalid devfile", func() {
|
||||
helper.Cmd("odo", "push", "--project", commonVar.Project, "--devfile", "invalid.yaml").ShouldFail()
|
||||
})
|
||||
})
|
||||
|
||||
When("Create and push java-springboot component", func() {
|
||||
BeforeEach(func() {
|
||||
helper.Cmd("odo", "create", "--project", commonVar.Project, cmpName, "--devfile", helper.GetExamplePath("source", "devfiles", "springboot", "devfile.yaml")).ShouldPass()
|
||||
helper.CopyExample(filepath.Join("source", "devfiles", "springboot", "project"), commonVar.Context)
|
||||
helper.Cmd("odo", "push", "--project", commonVar.Project).ShouldPass()
|
||||
})
|
||||
It("should execute default build and run commands correctly", func() {
|
||||
|
||||
podName := commonVar.CliRunner.GetRunningPodNameByComponent(cmpName, commonVar.Project)
|
||||
|
||||
var statErr error
|
||||
var cmdOutput string
|
||||
commonVar.CliRunner.CheckCmdOpInRemoteDevfilePod(
|
||||
podName,
|
||||
"runtime",
|
||||
commonVar.Project,
|
||||
// [s] to not match the current command: https://unix.stackexchange.com/questions/74185/how-can-i-prevent-grep-from-showing-up-in-ps-results
|
||||
[]string{"bash", "-c", "grep [s]pring-boot:run /proc/*/cmdline"},
|
||||
func(cmdOp string, err error) bool {
|
||||
cmdOutput = cmdOp
|
||||
statErr = err
|
||||
return err == nil
|
||||
},
|
||||
)
|
||||
Expect(statErr).ToNot(HaveOccurred())
|
||||
Expect(cmdOutput).To(MatchRegexp("Binary file .* matches"))
|
||||
})
|
||||
})
|
||||
|
||||
Context("devfile is modified", func() {
|
||||
// Tests https://github.com/redhat-developer/odo/issues/3838
|
||||
ensureFilesSyncedTest := func(namespace string, shouldForcePush bool) {
|
||||
output := ""
|
||||
When("java-springboot application is created and pushed", func() {
|
||||
BeforeEach(func() {
|
||||
helper.Cmd("odo", "create", "--project", commonVar.Project, cmpName, "--devfile", helper.GetExamplePath("source", "devfiles", "springboot", "devfile-registry.yaml")).ShouldPass()
|
||||
helper.CopyExample(filepath.Join("source", "devfiles", "springboot", "project"), commonVar.Context)
|
||||
|
||||
fmt.Fprintf(GinkgoWriter, "Testing with force push %v", shouldForcePush)
|
||||
output = helper.Cmd("odo", "push", "--project", commonVar.Project).ShouldPass().Out()
|
||||
})
|
||||
|
||||
It("should push the component successfully", func() {
|
||||
Expect(output).To(ContainSubstring("Changes successfully pushed to component"))
|
||||
})
|
||||
|
||||
When("Update the devfile.yaml, do odo push", func() {
|
||||
|
||||
BeforeEach(func() {
|
||||
helper.ReplaceString("devfile.yaml", "memoryLimit: 768Mi", "memoryLimit: 769Mi")
|
||||
commands := []string{"push", "-v", "4", "--project", commonVar.Project}
|
||||
if shouldForcePush {
|
||||
commands = append(commands, "-f")
|
||||
}
|
||||
|
||||
output = helper.Cmd("odo", commands...).ShouldPass().Out()
|
||||
})
|
||||
|
||||
It("Ensure the build passes", func() {
|
||||
Expect(output).To(ContainSubstring("BUILD SUCCESS"))
|
||||
})
|
||||
|
||||
When("compare the local and remote files", func() {
|
||||
|
||||
remoteFiles := []string{}
|
||||
localFiles := []string{}
|
||||
|
||||
BeforeEach(func() {
|
||||
podName := commonVar.CliRunner.GetRunningPodNameByComponent(cmpName, namespace)
|
||||
output = commonVar.CliRunner.Exec(podName, namespace, "find", sourcePath)
|
||||
outputArr := strings.Split(output, "\n")
|
||||
for _, line := range outputArr {
|
||||
|
||||
if !strings.HasPrefix(line, sourcePath+"/") || strings.Contains(line, "lost+found") {
|
||||
continue
|
||||
}
|
||||
|
||||
newLine, err := filepath.Rel(sourcePath, line)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
newLine = filepath.ToSlash(newLine)
|
||||
if strings.HasPrefix(newLine, "target/") || newLine == "target" || strings.HasPrefix(newLine, ".") {
|
||||
continue
|
||||
}
|
||||
|
||||
remoteFiles = append(remoteFiles, newLine)
|
||||
}
|
||||
|
||||
// 5) Acquire file from local context, filtering out .*
|
||||
err := filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
newPath := filepath.ToSlash(path)
|
||||
|
||||
if strings.HasPrefix(newPath, ".") {
|
||||
return nil
|
||||
}
|
||||
|
||||
localFiles = append(localFiles, newPath)
|
||||
return nil
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
|
||||
It("localFiles and remoteFiles should match", func() {
|
||||
sort.Strings(localFiles)
|
||||
sort.Strings(remoteFiles)
|
||||
Expect(localFiles).To(Equal(remoteFiles))
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
Context("odo push -f is executed", func() {
|
||||
ensureFilesSyncedTest(commonVar.Project, true)
|
||||
})
|
||||
Context("odo push (without -f) is executed", func() {
|
||||
ensureFilesSyncedTest(commonVar.Project, false)
|
||||
})
|
||||
|
||||
When("node-js application is created and pushed with devfile schema 2.2.0", func() {
|
||||
|
||||
var output string
|
||||
BeforeEach(func() {
|
||||
helper.Cmd("odo", "create", "--project", commonVar.Project, cmpName, "--devfile", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile-with-MR-CL-CR.yaml")).ShouldPass()
|
||||
helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), commonVar.Context)
|
||||
output = helper.Cmd("odo", "push", "--project", commonVar.Project).ShouldPass().Out()
|
||||
})
|
||||
|
||||
ensureResource := func(output, cpulimit, cpurequest, memoryrequest string) {
|
||||
By("check for cpuLimit", func() {
|
||||
podName := commonVar.CliRunner.GetRunningPodNameByComponent(cmpName, commonVar.Project)
|
||||
bufferOutput := commonVar.CliRunner.Run("get", "pods", podName, "-o", "jsonpath='{.spec.containers[0].resources.limits.cpu}'").Out.Contents()
|
||||
output = string(bufferOutput)
|
||||
Expect(output).To(ContainSubstring(cpulimit))
|
||||
})
|
||||
|
||||
By("check for cpuRequests", func() {
|
||||
podName := commonVar.CliRunner.GetRunningPodNameByComponent(cmpName, commonVar.Project)
|
||||
bufferOutput := commonVar.CliRunner.Run("get", "pods", podName, "-o", "jsonpath='{.spec.containers[0].resources.requests.cpu}'").Out.Contents()
|
||||
output = string(bufferOutput)
|
||||
Expect(output).To(ContainSubstring(cpurequest))
|
||||
})
|
||||
|
||||
By("check for memoryRequests", func() {
|
||||
podName := commonVar.CliRunner.GetRunningPodNameByComponent(cmpName, commonVar.Project)
|
||||
bufferOutput := commonVar.CliRunner.Run("get", "pods", podName, "-o", "jsonpath='{.spec.containers[0].resources.requests.memory}'").Out.Contents()
|
||||
output = string(bufferOutput)
|
||||
Expect(output).To(ContainSubstring(memoryrequest))
|
||||
})
|
||||
}
|
||||
|
||||
It("should check cpuLimit,cpuRequests,memoryRequests", func() {
|
||||
ensureResource(output, "1", "200m", "512Mi")
|
||||
})
|
||||
|
||||
When("Update the devfile.yaml, do odo push", func() {
|
||||
|
||||
BeforeEach(func() {
|
||||
helper.ReplaceString("devfile.yaml", "cpuLimit: \"1\"", "cpuLimit: 700m")
|
||||
helper.ReplaceString("devfile.yaml", "cpuRequest: 200m", "cpuRequest: 250m")
|
||||
helper.ReplaceString("devfile.yaml", "memoryRequest: 512Mi", "memoryRequest: 550Mi")
|
||||
output = helper.Cmd("odo", "push", "--project", commonVar.Project).ShouldPass().Out()
|
||||
})
|
||||
|
||||
It("should check cpuLimit,cpuRequests,memoryRequests", func() {
|
||||
ensureResource(output, "700m", "250m", "550Mi")
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
When("creating nodejs component, doing odo push and run command has dev.odo.push.path attribute", func() {
|
||||
BeforeEach(func() {
|
||||
helper.Cmd("odo", "create", cmpName, "--context", commonVar.Context, "--project", commonVar.Project, "--devfile", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile-with-remote-attributes.yaml")).ShouldPass()
|
||||
|
||||
helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), commonVar.Context)
|
||||
|
||||
// create a folder and file which shouldn't be pushed
|
||||
helper.MakeDir(filepath.Join(commonVar.Context, "views"))
|
||||
_, _ = helper.CreateSimpleFile(filepath.Join(commonVar.Context, "views"), "view", ".html")
|
||||
|
||||
helper.ReplaceString("package.json", "node server.js", "node server/server.js")
|
||||
helper.Cmd("odo", "push", "--context", commonVar.Context).ShouldPass()
|
||||
})
|
||||
It("should push only the mentioned files at the appropriate remote destination", func() {
|
||||
|
||||
podName := commonVar.CliRunner.GetRunningPodNameByComponent(cmpName, commonVar.Project)
|
||||
stdOut := commonVar.CliRunner.ExecListDir(podName, commonVar.Project, sourcePath)
|
||||
helper.MatchAllInOutput(stdOut, []string{"package.json", "server"})
|
||||
helper.DontMatchAllInOutput(stdOut, []string{"test", "views", "devfile.yaml"})
|
||||
|
||||
stdOut = commonVar.CliRunner.ExecListDir(podName, commonVar.Project, sourcePath+"/server")
|
||||
helper.MatchAllInOutput(stdOut, []string{"server.js", "test"})
|
||||
|
||||
helper.Cmd("odo", "push", "--context", commonVar.Context).ShouldPass()
|
||||
})
|
||||
})
|
||||
|
||||
Context("using OpenShift cluster", func() {
|
||||
BeforeEach(func() {
|
||||
if os.Getenv("KUBERNETES") == "true" {
|
||||
Skip("This is a OpenShift specific scenario, skipping")
|
||||
}
|
||||
})
|
||||
When("project with with 'default' name is used", func() {
|
||||
It("should throw an error", func() {
|
||||
componentName := helper.RandString(6)
|
||||
helper.CopyExample(filepath.Join("source", "nodejs"), commonVar.Context)
|
||||
helper.Cmd("odo", "create", "--project", "default", componentName, "--devfile", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile.yaml")).ShouldPass()
|
||||
|
||||
helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), commonVar.Context)
|
||||
|
||||
stdout := helper.Cmd("odo", "push").ShouldFail().Err()
|
||||
helper.MatchAllInOutput(stdout, []string{"odo may not work as expected in the default project, please run the odo component in a non-default project"})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Context("using Kubernetes cluster", func() {
|
||||
BeforeEach(func() {
|
||||
if os.Getenv("KUBERNETES") != "true" {
|
||||
Skip("This is a Kubernetes specific scenario, skipping")
|
||||
}
|
||||
})
|
||||
When("project with with 'default' name is used", func() {
|
||||
|
||||
It("should push successfully", func() {
|
||||
componentName := helper.RandString(6)
|
||||
helper.CopyExample(filepath.Join("source", "nodejs"), commonVar.Context)
|
||||
helper.Cmd("odo", "create", "--project", "default", componentName, "--devfile", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile.yaml")).ShouldPass()
|
||||
|
||||
helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), commonVar.Context)
|
||||
|
||||
stdout := helper.Cmd("odo", "push").ShouldPass().Out()
|
||||
helper.DontMatchAllInOutput(stdout, []string{"odo may not work as expected in the default project"})
|
||||
helper.Cmd("odo", "delete", "component", "-f", "--name", componentName, "--namespace", commonVar.Project).ShouldPass()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
@@ -61,7 +61,7 @@ var _ = Describe("odo devfile registry command tests", func() {
|
||||
})
|
||||
|
||||
It("should pass, when doing odo create with --registry flag", func() {
|
||||
helper.Cmd("odo", "create", "nodejs", "--registry", registryName).ShouldPass()
|
||||
helper.Cmd("odo", "init", "--name", "aname", "--devfile", "nodejs", "--devfile-registry", registryName).ShouldPass()
|
||||
})
|
||||
|
||||
It("should fail, when adding same registry", func() {
|
||||
@@ -80,7 +80,7 @@ var _ = Describe("odo devfile registry command tests", func() {
|
||||
|
||||
It("deleting registry and creating component with registry flag ", func() {
|
||||
helper.Cmd("odo", "preference", "registry", "delete", registryName, "-f").ShouldPass()
|
||||
helper.Cmd("odo", "create", "java-maven", "--registry", registryName).ShouldFail()
|
||||
helper.Cmd("odo", "init", "--name", "aname", "--devfile", "java-maven", "--devfile-registry", registryName).ShouldFail()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -98,26 +98,27 @@ var _ = Describe("odo devfile registry command tests", func() {
|
||||
|
||||
When("adding git based registries", func() {
|
||||
BeforeEach(func() {
|
||||
out, err = helper.Cmd("odo", "preference", "registry", "add", "RegistryFromGitHub", "https://github.com/odo-devfiles/registry").ShouldPass().OutAndErr()
|
||||
out, err = helper.Cmd("odo", "preference", "registry", "add", "RegistryFromGitHub", "https://github.com/devfile/registry").ShouldPass().OutAndErr()
|
||||
|
||||
})
|
||||
It("should show deprication warning", func() {
|
||||
It("should show deprecation warning", func() {
|
||||
co = fmt.Sprintln(out, err)
|
||||
helper.MatchAllInOutput(co, []string{deprecated, docLink})
|
||||
|
||||
By("odo resgistry list is executed, should show the warning", func() {
|
||||
By("odo registry list is executed, should show the warning", func() {
|
||||
out, err = helper.Cmd("odo", "preference", "registry", "list").ShouldPass().OutAndErr()
|
||||
co = fmt.Sprintln(out, err)
|
||||
helper.MatchAllInOutput(co, []string{deprecated, docLink})
|
||||
})
|
||||
By("should successfully delete registry", func() {
|
||||
out, err = helper.Cmd("odo", "create", "nodejs", "--registry", "RegistryFromGitHub").ShouldPass().OutAndErr()
|
||||
co = fmt.Sprintln(out, err)
|
||||
helper.MatchAllInOutput(co, []string{deprecated, docLink})
|
||||
// TODO: Should `odo init` support GitHub based registries
|
||||
// By("should successfully delete registry", func() {
|
||||
// out, err = helper.Cmd("odo", "init", "--name", "aname", "--devfile", "nodejs", "--devfile-registry", "RegistryFromGitHub").ShouldPass().OutAndErr()
|
||||
// co = fmt.Sprintln(out, err)
|
||||
// helper.MatchAllInOutput(co, []string{deprecated, docLink})
|
||||
// })
|
||||
})
|
||||
})
|
||||
It("should not show deprication warning if git registry is not used for component creation", func() {
|
||||
out, err = helper.Cmd("odo", "create", "nodejs", "--registry", "DefaultDevfileRegistry").ShouldPass().OutAndErr()
|
||||
It("should not show deprecation warning if git registry is not used for component creation", func() {
|
||||
out, err = helper.Cmd("odo", "init", "--name", "aname", "--devfile", "nodejs", "--devfile-registry", "DefaultDevfileRegistry").ShouldPass().OutAndErr()
|
||||
helper.DontMatchAllInOutput(fmt.Sprintln(out, err), []string{deprecated, docLink})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,452 +0,0 @@
|
||||
package devfile
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/redhat-developer/odo/tests/helper"
|
||||
"github.com/tidwall/gjson"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("odo devfile url command tests", func() {
|
||||
var componentName string
|
||||
var commonVar helper.CommonVar
|
||||
url1 := helper.RandString(5)
|
||||
url1Port := "5000"
|
||||
url2 := helper.RandString(5)
|
||||
url2Port := "9000"
|
||||
// Required to ensure duplicate ports are not used to create a URL
|
||||
nodejsDevfilePort := "3000"
|
||||
nodejsDevfileURLName := "3000-tcp"
|
||||
springbootDevfilePort := "8080"
|
||||
portNumber := "3030"
|
||||
host := helper.RandString(5) + ".com"
|
||||
|
||||
// This is run before every Spec (It)
|
||||
var _ = BeforeEach(func() {
|
||||
commonVar = helper.CommonBeforeEach()
|
||||
componentName = helper.RandString(6)
|
||||
helper.Chdir(commonVar.Context)
|
||||
})
|
||||
|
||||
// This is run after every Spec (It)
|
||||
var _ = AfterEach(func() {
|
||||
helper.CommonAfterEach(commonVar)
|
||||
})
|
||||
|
||||
It("should error out on devfile flag", func() {
|
||||
helper.Cmd("odo", "url", "create", "mynodejs", "--devfile", "invalid.yaml").ShouldFail()
|
||||
helper.Cmd("odo", "url", "delete", "mynodejs", "--devfile", "invalid.yaml").ShouldFail()
|
||||
})
|
||||
|
||||
When("creating a Nodejs component", func() {
|
||||
var stdout string
|
||||
|
||||
BeforeEach(func() {
|
||||
helper.Cmd("odo", "create", "--project", commonVar.Project, componentName, "--devfile", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile.yaml")).ShouldPass()
|
||||
helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), commonVar.Context)
|
||||
})
|
||||
|
||||
It("should not allow creating an invalid host", func() {
|
||||
stdout = helper.Cmd("odo", "url", "create", "--host", "https://127.0.0.1:60104", "--port", portNumber, "--ingress").ShouldFail().Err()
|
||||
Expect(stdout).To(ContainSubstring("is not a valid host name"))
|
||||
})
|
||||
|
||||
It("should not allow using tls secret if url is not secure", func() {
|
||||
stdout = helper.Cmd("odo", "url", "create", "--tls-secret", "foo", "--port", portNumber, "--ingress").ShouldFail().Err()
|
||||
Expect(stdout).To(ContainSubstring("TLS secret is only available for secure URLs of Ingress kind"))
|
||||
})
|
||||
|
||||
It("should report multiple issues when it's the case", func() {
|
||||
stdout = helper.Cmd("odo", "url", "create", "--host", "https://127.0.0.1:60104", "--tls-secret", "foo", "--port", portNumber, "--ingress").ShouldFail().Err()
|
||||
Expect(stdout).To(And(ContainSubstring("is not a valid host name"), ContainSubstring("TLS secret is only available for secure URLs of Ingress kind")))
|
||||
})
|
||||
|
||||
It("should not allow to create URL with duplicate port", func() {
|
||||
stdout = helper.Cmd("odo", "url", "create", url1, "--port", nodejsDevfilePort).ShouldFail().Err()
|
||||
Expect(stdout).To(ContainSubstring("port 3000 already exists in devfile endpoint entry"))
|
||||
})
|
||||
|
||||
It("should not allow creating under an invalid container", func() {
|
||||
containerName := helper.RandString(5)
|
||||
stdout = helper.Cmd("odo", "url", "create", "--host", "com", "--port", portNumber, "--container", containerName, "--ingress").ShouldFail().Err()
|
||||
helper.MatchAllInOutput(stdout, []string{"container", containerName, "not exist"})
|
||||
})
|
||||
|
||||
It("should not allow creating an endpoint with same name", func() {
|
||||
stdout = helper.Cmd("odo", "url", "create", nodejsDevfileURLName, "--host", "com", "--port", nodejsDevfilePort, "--ingress").ShouldFail().Err()
|
||||
Expect(stdout).To(ContainSubstring(fmt.Sprintf("url %s already exists in devfile endpoint entry", nodejsDevfileURLName)))
|
||||
})
|
||||
|
||||
When("creating ingress url1 with port flag and doing odo push", func() {
|
||||
|
||||
BeforeEach(func() {
|
||||
helper.Cmd("odo", "url", "create", url1, "--port", url1Port, "--host", host, "--secure", "--ingress").ShouldPass()
|
||||
helper.Cmd("odo", "push").ShouldPass()
|
||||
})
|
||||
|
||||
It("should check state of url1 list", func() {
|
||||
stdout = helper.Cmd("odo", "url", "list").ShouldPass().Out()
|
||||
helper.MatchAllInOutput(stdout, []string{url1, "Pushed", "true", "ingress"})
|
||||
})
|
||||
It("should take user provided url name", func() {
|
||||
stdout = string(commonVar.CliRunner.Run("get", "svc", "--namespace", commonVar.Project, fmt.Sprintf("%v-%v", componentName, "app"), "-ojsonpath='{.spec.ports[*].name}'").Out.Contents())
|
||||
Expect(stdout).To(ContainSubstring(url1))
|
||||
})
|
||||
|
||||
When("creating ingress url2 with port flag and doing odo push", func() {
|
||||
BeforeEach(func() {
|
||||
helper.Cmd("odo", "url", "create", url2, "--port", url2Port, "--host", host, "--ingress").ShouldPass()
|
||||
stdout = helper.Cmd("odo", "url", "list").ShouldPass().Out()
|
||||
})
|
||||
It("should check state of url2", func() {
|
||||
helper.MatchAllInOutput(stdout, []string{url2, "Not Pushed", "false", "ingress"})
|
||||
})
|
||||
When("deleting url1", func() {
|
||||
BeforeEach(func() {
|
||||
helper.Cmd("odo", "url", "delete", url1, "-f").ShouldPass()
|
||||
stdout = helper.Cmd("odo", "url", "list").ShouldPass().Out()
|
||||
})
|
||||
It("should check status of url1 and url2", func() {
|
||||
helper.MatchAllInOutput(stdout, []string{url1, "Locally Deleted", "true", "ingress"})
|
||||
helper.MatchAllInOutput(stdout, []string{url2, "Not Pushed", "false", "ingress"})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
When("creating a url with -o json", func() {
|
||||
var createExpected []string
|
||||
var createValues []gjson.Result
|
||||
var createJSON string
|
||||
|
||||
BeforeEach(func() {
|
||||
helper.Cmd("odo", "url", "delete", nodejsDevfileURLName, "-f").ShouldPass()
|
||||
createJSON = helper.Cmd("odo", "url", "create", url1, "--port", nodejsDevfilePort, "--host", host, "--ingress", "-o", "json").ShouldPass().Out()
|
||||
|
||||
})
|
||||
|
||||
It("should validate machine readable output for url create", func() {
|
||||
createValues = gjson.GetMany(createJSON, "kind", "metadata.name", "spec.port", "status.state")
|
||||
createExpected = []string{"URL", url1, nodejsDevfilePort, "Not Pushed"}
|
||||
Expect(helper.GjsonMatcher(createValues, createExpected)).To(Equal(true))
|
||||
})
|
||||
|
||||
When("doing odo push", func() {
|
||||
BeforeEach(func() {
|
||||
helper.Cmd("odo", "push", "--project", commonVar.Project).ShouldPass()
|
||||
})
|
||||
It("validate machine readable output for url list", func() {
|
||||
helper.WaitForCmdOut("odo", []string{"url", "list", "-o", "json"}, 1, true, func(output string) bool {
|
||||
if strings.Contains(output, url1) {
|
||||
values := gjson.GetMany(output, "kind", "items.0.kind", "items.0.metadata.name", "items.0.spec.host", "items.0.status.state")
|
||||
expected := []string{"List", "URL", url1, url1, "Pushed"}
|
||||
Expect(helper.GjsonMatcher(values, expected)).To(Equal(true))
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
XWhen("creating a URL without port flag", func() {
|
||||
// marking it as pending, since we want to start using port number as a key to URLs in devfile,
|
||||
// FIXME: and odo should not allow using url create without a port number, this should be taken care of in v3-alpha2
|
||||
|
||||
BeforeEach(func() {
|
||||
helper.Cmd("odo", "url", "create", url1, "--host", host, "--ingress").ShouldPass()
|
||||
stdout = helper.Cmd("odo", "url", "list").ShouldPass().Out()
|
||||
})
|
||||
It("should create a URL without port flag if only one port exposed in devfile", func() {
|
||||
helper.MatchAllInOutput(stdout, []string{url1, "3000", "Not Pushed"})
|
||||
})
|
||||
})
|
||||
|
||||
When("creating a secure URL and doing odo push", func() {
|
||||
BeforeEach(func() {
|
||||
helper.Cmd("odo", "url", "create", url1, "--port", url1Port, "--host", host, "--secure", "--ingress").ShouldPass()
|
||||
stdout = helper.Cmd("odo", "push", "--project", commonVar.Project).ShouldPass().Out()
|
||||
})
|
||||
It("should list secure URL", func() {
|
||||
stdout = helper.Cmd("odo", "url", "list").ShouldPass().Out()
|
||||
helper.MatchAllInOutput(stdout, []string{"https:", url1 + "." + host, "true"})
|
||||
})
|
||||
})
|
||||
|
||||
When("create with now flag", func() {
|
||||
BeforeEach(func() {
|
||||
helper.Cmd("odo", "url", "create", url1, "--port", url1Port, "--host", host, "--now", "--ingress").ShouldPass()
|
||||
})
|
||||
It("should check if url created for component", func() {
|
||||
// check the env for the runMode
|
||||
envOutput, err := helper.ReadFile(filepath.Join(commonVar.Context, ".odo/env/env.yaml"))
|
||||
Expect(err).To(BeNil())
|
||||
Expect(envOutput).To(ContainSubstring(" RunMode: run"))
|
||||
})
|
||||
})
|
||||
|
||||
When("creating a url and doing odo push twice", func() {
|
||||
BeforeEach(func() {
|
||||
helper.Cmd("odo", "url", "create", url1, "--port", url1Port, "--host", host, "--ingress").ShouldPass()
|
||||
helper.Cmd("odo", "push", "--project", commonVar.Project).ShouldPass()
|
||||
})
|
||||
It("should be able to push again twice", func() {
|
||||
helper.Cmd("odo", "push", "--project", commonVar.Project).ShouldPass()
|
||||
})
|
||||
When("deleting url and doing odo push twice", func() {
|
||||
BeforeEach(func() {
|
||||
helper.Cmd("odo", "push", "--project", commonVar.Project).ShouldPass()
|
||||
helper.Cmd("odo", "url", "delete", url1, "-f").ShouldPass()
|
||||
helper.Cmd("odo", "push", "--project", commonVar.Project).ShouldPass()
|
||||
})
|
||||
It("should be able to push again twice", func() {
|
||||
helper.Cmd("odo", "push", "--project", commonVar.Project).ShouldPass()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
When("executing odo outside of context", func() {
|
||||
subFolderContext := ""
|
||||
BeforeEach(func() {
|
||||
subFolderContext = filepath.Join(commonVar.Context, helper.RandString(6))
|
||||
helper.MakeDir(subFolderContext)
|
||||
helper.Chdir(subFolderContext)
|
||||
})
|
||||
|
||||
It("should fail if url is created from non context dir", func() {
|
||||
stdout = helper.Cmd("odo", "url", "create", url1, "--port", url1Port, "--host", host, "--ingress").ShouldFail().Err()
|
||||
Expect(stdout).To(ContainSubstring("The current directory does not represent an odo component"))
|
||||
})
|
||||
It("should fail if host flag not provided with ingress flag", func() {
|
||||
stdout = helper.Cmd("odo", "url", "create", url1, "--port", url1Port, "--ingress", "--context", commonVar.Context).ShouldFail().Err()
|
||||
Expect(stdout).To(ContainSubstring("host must be provided"))
|
||||
})
|
||||
|
||||
When("creating url1,url2 and doing odo push with context flag", func() {
|
||||
BeforeEach(func() {
|
||||
helper.Cmd("odo", "url", "create", url2, "--port", url2Port, "--host", host, "--ingress", "--context", commonVar.Context).ShouldPass()
|
||||
helper.Cmd("odo", "url", "create", url1, "--port", url1Port, "--host", host, "--ingress", "--context", commonVar.Context).ShouldPass()
|
||||
stdout = helper.Cmd("odo", "push", "--context", commonVar.Context).ShouldPass().Out()
|
||||
})
|
||||
When("doing url list", func() {
|
||||
BeforeEach(func() {
|
||||
stdout = helper.Cmd("odo", "url", "list", "--context", commonVar.Context).ShouldPass().Out()
|
||||
})
|
||||
It("should successfully push url1 and url2", func() {
|
||||
helper.MatchAllInOutput(stdout, []string{url1, url2, "Pushed", "false", "ingress"})
|
||||
})
|
||||
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
When("creating a java-springboot component", func() {
|
||||
var stdout string
|
||||
BeforeEach(func() {
|
||||
helper.Cmd("odo", "create", "--project", commonVar.Project, componentName, "--devfile", helper.GetExamplePath("source", "devfiles", "springboot", "devfile.yaml")).ShouldPass()
|
||||
helper.CopyExample(filepath.Join("source", "devfiles", "springboot", "project"), commonVar.Context)
|
||||
})
|
||||
|
||||
XWhen("create URLs under different container names with same port number", func() {
|
||||
// marking it as pending, since the current behavior of odo url create is buggy, this should be fixed in odo v3-alpha2
|
||||
BeforeEach(func() {
|
||||
stdout = helper.Cmd("odo", "url", "create", url1, "--port", "8080", "--host", host, "--container", "tools", "--ingress").ShouldFail().Err()
|
||||
})
|
||||
It("should not create URLs under different container names with same port number", func() {
|
||||
helper.MatchAllInOutput(stdout, []string{fmt.Sprintf("cannot set URL %s under container tools", url1), fmt.Sprintf("TargetPort %s is being used under container runtime", springbootDevfilePort)})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
When("Creating nodejs component and url with .devfile.yaml", func() {
|
||||
var stdout string
|
||||
BeforeEach(func() {
|
||||
helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile.yaml"), filepath.Join(commonVar.Context, ".devfile.yaml"))
|
||||
helper.Cmd("odo", "create", "--project", commonVar.Project, componentName).ShouldPass()
|
||||
helper.CopyExample(filepath.Join("source", "devfiles", "springboot", "project"), commonVar.Context)
|
||||
stdout = helper.Cmd("odo", "url", "create", url1, "--port", url1Port, "--host", host, "--container", "runtime", "--ingress").ShouldPass().Out()
|
||||
})
|
||||
|
||||
It("should create url", func() {
|
||||
helper.MatchAllInOutput(stdout, []string{url1, "created"})
|
||||
})
|
||||
When("listing url", func() {
|
||||
BeforeEach(func() {
|
||||
stdout = helper.Cmd("odo", "url", "list", "--context", commonVar.Context).ShouldPass().Out()
|
||||
})
|
||||
It("should list urls", func() {
|
||||
helper.MatchAllInOutput(stdout, []string{url1, "Pushed", "false", "ingress"})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Context("Testing URLs for OpenShift specific scenarios", func() {
|
||||
|
||||
stdout := ""
|
||||
BeforeEach(func() {
|
||||
if os.Getenv("KUBERNETES") == "true" {
|
||||
Skip("This is a OpenShift specific scenario, skipping")
|
||||
}
|
||||
})
|
||||
|
||||
When("creating a nodejs component", func() {
|
||||
ingressurl := helper.RandString(5)
|
||||
|
||||
BeforeEach(func() {
|
||||
helper.Cmd("odo", "create", "--project", commonVar.Project, componentName, "--devfile", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile.yaml")).ShouldPass()
|
||||
helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), commonVar.Context)
|
||||
})
|
||||
|
||||
It("should error out when a host is provided with a route on a openShift cluster", func() {
|
||||
output := helper.Cmd("odo", "url", "create", url1, "--host", "com", "--port", portNumber).ShouldFail().Err()
|
||||
Expect(output).To(ContainSubstring("host is not supported"))
|
||||
})
|
||||
|
||||
When("creating multiple url with different state", func() {
|
||||
BeforeEach(func() {
|
||||
helper.Cmd("odo", "url", "create", url1, "--port", url1Port, "--secure").ShouldPass()
|
||||
helper.Cmd("odo", "url", "create", ingressurl, "--port", portNumber, "--host", host, "--ingress").ShouldPass()
|
||||
helper.Cmd("odo", "push", "--project", commonVar.Project).ShouldPass()
|
||||
helper.Cmd("odo", "url", "create", url2, "--port", url2Port).ShouldPass()
|
||||
})
|
||||
|
||||
It("should list route and ingress urls with appropriate state", func() {
|
||||
stdout = helper.Cmd("odo", "url", "list").ShouldPass().Out()
|
||||
helper.MatchAllInOutput(stdout, []string{url1, "Pushed", "true", "route"})
|
||||
helper.MatchAllInOutput(stdout, []string{url2, "Not Pushed", "false", "route"})
|
||||
helper.MatchAllInOutput(stdout, []string{ingressurl, "Pushed", "false", "ingress"})
|
||||
})
|
||||
|
||||
When("url1 is deleted locally", func() {
|
||||
|
||||
BeforeEach(func() {
|
||||
helper.Cmd("odo", "url", "delete", url1, "-f").ShouldPass()
|
||||
stdout = helper.Cmd("odo", "url", "list").ShouldPass().Out()
|
||||
})
|
||||
|
||||
It("should list route and ingress urls with appropriate state", func() {
|
||||
helper.MatchAllInOutput(stdout, []string{url1, "Locally Deleted", "true", "route"})
|
||||
helper.MatchAllInOutput(stdout, []string{url2, "Not Pushed", "false", "route"})
|
||||
helper.MatchAllInOutput(stdout, []string{ingressurl, "Pushed", "false", "ingress"})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
XIt("should automatically create route on a openShift cluster", func() {
|
||||
// marking it as pending, since current odo url create behavior is buggy, and this should be taken care of in v3-alpha2
|
||||
helper.Cmd("odo", "url", "create", url1, "--port", nodejsDevfilePort).ShouldPass()
|
||||
fileOutput, err := helper.ReadFile(filepath.Join(commonVar.Context, "devfile.yaml"))
|
||||
Expect(err).To(BeNil())
|
||||
helper.MatchAllInOutput(fileOutput, []string{nodejsDevfileURLName, nodejsDevfilePort})
|
||||
})
|
||||
|
||||
When("doing odo push twice and doing url list", func() {
|
||||
BeforeEach(func() {
|
||||
helper.Cmd("odo", "url", "create", url1, "--port", url1Port).ShouldPass()
|
||||
helper.Cmd("odo", "push", "--project", commonVar.Project).ShouldPass()
|
||||
helper.Cmd("odo", "push", "--project", commonVar.Project).ShouldPass()
|
||||
stdout = helper.Cmd("odo", "url", "list").ShouldPass().Out()
|
||||
})
|
||||
|
||||
It("should push successfully", func() {
|
||||
Expect(stdout).Should(ContainSubstring(url1))
|
||||
})
|
||||
|
||||
When("deleting the url1 and doing odo push twice and doing url list", func() {
|
||||
|
||||
BeforeEach(func() {
|
||||
helper.Cmd("odo", "url", "delete", url1, "-f").ShouldPass()
|
||||
helper.Cmd("odo", "push", "--project", commonVar.Project).ShouldPass()
|
||||
helper.Cmd("odo", "push", "--project", commonVar.Project).ShouldPass()
|
||||
stdout = helper.Cmd("odo", "url", "list").ShouldPass().Out()
|
||||
})
|
||||
|
||||
It("should push successfully", func() {
|
||||
Expect(stdout).ShouldNot(ContainSubstring(url1))
|
||||
})
|
||||
})
|
||||
})
|
||||
When("doing odo push", func() {
|
||||
BeforeEach(func() {
|
||||
helper.Cmd("odo", "push", "--project", commonVar.Project).ShouldPass()
|
||||
stdout = helper.Cmd("odo", "url", "list").ShouldPass().Out()
|
||||
})
|
||||
|
||||
It("should create a route on a openShift cluster without calling url create", func() {
|
||||
Expect(stdout).Should(ContainSubstring("3000-tcp"))
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
When("creating a python component", func() {
|
||||
BeforeEach(func() {
|
||||
helper.CopyExample(filepath.Join("source", "python"), commonVar.Context)
|
||||
helper.Chdir(commonVar.Context)
|
||||
helper.Cmd("odo", "create", "--project", commonVar.Project, componentName, "--devfile", helper.GetExamplePath("source", "devfiles", "python", "devfile-registry.yaml")).ShouldPass()
|
||||
})
|
||||
|
||||
When("creating a url and doing odo push", func() {
|
||||
var output string
|
||||
BeforeEach(func() {
|
||||
helper.Cmd("odo", "url", "create", url1, "--port", "5000", "--host", "com", "--ingress").ShouldPass()
|
||||
helper.Cmd("odo", "push", "--project", commonVar.Project).ShouldPass()
|
||||
})
|
||||
|
||||
It("should create a url for a unsupported devfile component", func() {
|
||||
output = helper.Cmd("odo", "url", "list").ShouldPass().Out()
|
||||
Expect(output).Should(ContainSubstring(url1))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
XContext("Testing URLs for Kubernetes specific scenarios", func() {
|
||||
// TODO: marking it as pending, since current odo url create behavior is buggy, and this should be taken care of in v3-alpha2
|
||||
BeforeEach(func() {
|
||||
if os.Getenv("KUBERNETES") != "true" {
|
||||
Skip("This is a Kubernetes specific scenario, skipping")
|
||||
}
|
||||
})
|
||||
|
||||
When("creating a nodejs component", func() {
|
||||
BeforeEach(func() {
|
||||
helper.Cmd("odo", "create", "--project", commonVar.Project, componentName, "--devfile", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile.yaml")).ShouldPass()
|
||||
helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), commonVar.Context)
|
||||
})
|
||||
|
||||
When("creating url", func() {
|
||||
BeforeEach(func() {
|
||||
helper.Cmd("odo", "url", "create", "--host", "com", "--port", nodejsDevfilePort).ShouldPass()
|
||||
})
|
||||
|
||||
When("creating a second url", func() {
|
||||
|
||||
BeforeEach(func() {
|
||||
helper.Cmd("odo", "url", "create", url1, "--host", "com", "--port", url1Port).ShouldPass()
|
||||
})
|
||||
|
||||
It("should use an existing URL when there are URLs with no host defined in the env file with same port", func() {
|
||||
fileOutput, err := helper.ReadFile(filepath.Join(commonVar.Context, "devfile.yaml"))
|
||||
Expect(err).To(BeNil())
|
||||
helper.MatchAllInOutput(fileOutput, []string{url1, url1Port})
|
||||
count := strings.Count(fileOutput, "targetPort")
|
||||
Expect(count).To(Equal(2))
|
||||
})
|
||||
})
|
||||
It("should verify", func() {
|
||||
fileOutput, err := helper.ReadFile(filepath.Join(commonVar.Context, "devfile.yaml"))
|
||||
Expect(err).To(BeNil())
|
||||
helper.MatchAllInOutput(fileOutput, []string{nodejsDevfileURLName, nodejsDevfilePort})
|
||||
count := strings.Count(fileOutput, "targetPort")
|
||||
Expect(count).To(Equal(1))
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,60 +0,0 @@
|
||||
package devfile
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
|
||||
//We continued iterating on bracket pair guides. Horizontal lines now outline the scope of a bracket pair. Also, vertical lines now depend on the indentation of the code that is surrounded by the bracket pair.. "github.com/onsi/gomega"
|
||||
"github.com/redhat-developer/odo/tests/helper"
|
||||
)
|
||||
|
||||
var _ = Describe("Test suits to check .devfile.yaml compatibility", func() {
|
||||
var cmpName string
|
||||
var commonVar helper.CommonVar
|
||||
|
||||
BeforeEach(func() {
|
||||
commonVar = helper.CommonBeforeEach()
|
||||
cmpName = helper.RandString(6)
|
||||
helper.Chdir(commonVar.Context)
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
helper.CommonAfterEach(commonVar)
|
||||
})
|
||||
|
||||
When("Creating a nodejs component and replace devfile.yaml to .devfile.yaml", func() {
|
||||
var _ = BeforeEach(func() {
|
||||
helper.Cmd("odo", "create", "--project", commonVar.Project, cmpName, "--devfile", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile.yaml")).ShouldPass()
|
||||
helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), commonVar.Context)
|
||||
helper.Cmd("mv", "devfile.yaml", ".devfile.yaml").ShouldPass()
|
||||
})
|
||||
|
||||
When("Creating url and doing odo push", func() {
|
||||
var stdout, url1, host string
|
||||
|
||||
BeforeEach(func() {
|
||||
url1 = helper.RandString(6)
|
||||
host = helper.RandString(6)
|
||||
helper.Cmd("odo", "url", "create", url1, "--port", "9090", "--host", host, "--secure", "--ingress").ShouldPass()
|
||||
helper.Cmd("odo", "push").ShouldPass()
|
||||
})
|
||||
|
||||
It("should verify if url is created and pushed", func() {
|
||||
stdout = helper.Cmd("odo", "url", "list").ShouldPass().Out()
|
||||
helper.MatchAllInOutput(stdout, []string{url1, "Pushed", "true", "ingress"})
|
||||
})
|
||||
When("Deleting url doing odo push", func() {
|
||||
|
||||
BeforeEach(func() {
|
||||
helper.Cmd("odo", "url", "delete", url1, "-f").ShouldPass()
|
||||
})
|
||||
|
||||
It("should verify if url is created and pushed", func() {
|
||||
stdout = helper.Cmd("odo", "url", "list").ShouldPass().Out()
|
||||
helper.MatchAllInOutput(stdout, []string{url1, "Locally Deleted", "true", "ingress"})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user