Allow fetching specific devfile stack version (#6429)

* Ask for stack version in the interactive mode; downloading still doesn't work as expected

Signed-off-by: Parthvi Vala <pvala@redhat.com>

* Download the versioned Devfile for interactive mode

* Download the versioned Devfile for flag mode

* Download the versioned Devfile for the alizer mode

* Add support for 'latest' stack

* Update init automation message with devfile-version

* Mark the default version in interactive mode

* Fix interactive tests

Signed-off-by: Parthvi Vala <pvala@redhat.com>

* Add integration tests for odo init flag mode

* Fix unit and validation tests

Signed-off-by: Parthvi Vala <pvala@redhat.com>

* Add to the documentation

Signed-off-by: Parthvi Vala <pvala@redhat.com>

* Add information about the default version

Signed-off-by: Parthvi Vala <pvala@redhat.com>
This commit is contained in:
Parthvi Vala
2022-12-21 19:44:40 +05:30
committed by GitHub
parent 46abd92226
commit 0d392ef5bd
21 changed files with 274 additions and 56 deletions

View File

@@ -107,7 +107,9 @@ Changes will be directly reflected on the cluster.
In non-interactive mode, you will have to specify from the command-line the information needed to get a devfile.
If you want to download a devfile from a registry, you must specify the devfile name with the `--devfile` flag. The devfile with the specified name will be searched in the registries referenced (using `odo preference view`), and the first one matching will be downloaded. If you want to download the devfile from a specific registry in the list or referenced registries, you can use the `--devfile-registry` flag to specify the name of this registry. By default odo uses official devfile registry [registry.devfile.io](https://registry.devfile.io). You can use registry's [web interface](https://registry.devfile.io/viewer) to view its content.
If you want to download a devfile from a registry, you must specify the devfile name with the `--devfile` flag. The devfile with the specified name will be searched in the registries referenced (using `odo preference view`), and the first one matching will be downloaded.
If you want to download the devfile from a specific registry in the list or referenced registries, you can use the `--devfile-registry` flag to specify the name of this registry. By default odo uses official devfile registry [registry.devfile.io](https://registry.devfile.io). You can use registry's [web interface](https://registry.devfile.io/viewer) to view its content.
If you want to download a version devfile, you must specify the version with `--devfile-version` flag.
If you prefer to download a devfile from an URL or from the local filesystem, you can use the `--devfile-path` instead.
@@ -115,7 +117,7 @@ The `--starter` flag indicates the name of the starter project (as referenced in
The required `--name` flag indicates how the component initialized by this command should be named. The name must follow the [Kubernetes naming convention](https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#dns-label-names) and not be all-numeric.
#### Non-interactive mode from any registry of the list
#### Fetch Devfile from any registry of the list
In this example, the devfile will be downloaded from the **Staging** registry, which is the first one in the list containing the `nodejs-react` devfile.
```shell
@@ -136,7 +138,7 @@ Devfile registries:
</details>
#### Non-interactive mode from a specific registry of the list
#### Fetch Devfile from a specific registry of the list
In this example, the devfile will be downloaded from the **DefaultDevfileRegistry** registry, as explicitly indicated by the `--devfile-registry` flag.
<details>
@@ -165,7 +167,7 @@ To deploy your component to a cluster use "odo deploy".
</details>
#### Non-interactive mode from a URL
#### Fetch Devfile from a URL
```console
odo init --devfile-path <URL> --name <component-name> [--starter STARTER]
@@ -185,3 +187,53 @@ To deploy your component to a cluster use "odo deploy".
```
</details>
#### Fetch Devfile of a specific version
```console
odo init --devfile <devfile-name> --devfile-version <devfile-version> --name <component-name> [--starter STARTER]
```
<details>
<summary>Examples</summary>
```console
$ odo init --devfile go --name my-go-app --devfile-version 2.0.0
__
/ \__ Initializing a new component
\__/ \
/ \__/ odo version: v3.4.0
\__/
✓ Downloading devfile "go:2.0.0" [4s]
Your new component 'my-go-app' is ready in the current directory.
To start editing your component, use 'odo dev' and open this folder in your favorite IDE.
Changes will be directly reflected on the cluster.
To deploy your component to a cluster use "odo deploy".
```
</details>
:::note
Use "latest" as the version name to fetch the latest version of a given Devfile.
<details>
<summary>Example</summary>
```console
$ odo init --devfile go --name my-go-app --devfile-version latest
__
/ \__ Initializing a new component
\__/ \
/ \__/ odo version: v3.4.0
\__/
✓ Downloading devfile "go:latest" [4s]
Your new component 'my-go-app' is ready in the current directory.
To start editing your component, use 'odo dev' and open this folder in your favorite IDE.
Changes will be directly reflected on the cluster.
To deploy your component to a cluster use "odo deploy".
```
</details>
:::

View File

@@ -8,10 +8,11 @@ import (
"github.com/redhat-developer/alizer/go/pkg/apis/model"
"github.com/redhat-developer/alizer/go/pkg/apis/recognizer"
"k8s.io/klog"
"github.com/redhat-developer/odo/pkg/api"
"github.com/redhat-developer/odo/pkg/registry"
"github.com/redhat-developer/odo/pkg/util"
"k8s.io/klog"
)
type Alizer struct {
@@ -28,11 +29,11 @@ func NewAlizerClient(registryClient registry.Client) *Alizer {
// DetectFramework uses the alizer library in order to detect the devfile
// to use depending on the files in the path
func (o *Alizer) DetectFramework(ctx context.Context, path string) (model.DevFileType, api.Registry, error) {
func (o *Alizer) DetectFramework(ctx context.Context, path string) (_ model.DevFileType, defaultVersion string, _ api.Registry, _ error) {
types := []model.DevFileType{}
components, err := o.registryClient.ListDevfileStacks(ctx, "", "", "", false)
if err != nil {
return model.DevFileType{}, api.Registry{}, err
return model.DevFileType{}, defaultVersion, api.Registry{}, err
}
for _, component := range components.Items {
types = append(types, model.DevFileType{
@@ -44,9 +45,15 @@ func (o *Alizer) DetectFramework(ctx context.Context, path string) (model.DevFil
}
typ, err := recognizer.SelectDevFileFromTypes(path, types)
if err != nil {
return model.DevFileType{}, api.Registry{}, err
return model.DevFileType{}, defaultVersion, api.Registry{}, err
}
return types[typ], components.Items[typ].Registry, nil
// Get the default stack version that will be downloaded
for _, version := range components.Items[typ].Versions {
if version.IsDefault {
defaultVersion = version.Version
}
}
return types[typ], defaultVersion, components.Items[typ].Registry, nil
}
// DetectName retrieves the name of the project (if available).
@@ -131,10 +138,11 @@ func (o *Alizer) DetectPorts(path string) ([]int, error) {
return components[0].Ports, nil
}
func NewDetectionResult(typ model.DevFileType, registry api.Registry, appPorts []int) *api.DetectionResult {
func NewDetectionResult(typ model.DevFileType, registry api.Registry, appPorts []int, devfileVersion string) *api.DetectionResult {
return &api.DetectionResult{
Devfile: typ.Name,
DevfileRegistry: registry.Name,
ApplicationPorts: appPorts,
DevfileVersion: devfileVersion,
}
}

View File

@@ -119,7 +119,7 @@ func TestDetectFramework(t *testing.T) {
registryClient.EXPECT().ListDevfileStacks(ctx, "", "", "", false).Return(list, nil)
alizerClient := NewAlizerClient(registryClient)
// Run function DetectFramework
detected, registry, err := alizerClient.DetectFramework(ctx, tt.args.path)
detected, _, registry, err := alizerClient.DetectFramework(ctx, tt.args.path)
if !tt.wantErr == (err != nil) {
t.Errorf("unexpected error %v, wantErr %v", err, tt.wantErr)

View File

@@ -4,11 +4,12 @@ import (
"context"
"github.com/redhat-developer/alizer/go/pkg/apis/model"
"github.com/redhat-developer/odo/pkg/api"
)
type Client interface {
DetectFramework(ctx context.Context, path string) (model.DevFileType, api.Registry, error)
DetectFramework(ctx context.Context, path string) (_ model.DevFileType, defaultVersion string, _ api.Registry, _ error)
DetectName(path string) (string, error)
DetectPorts(path string) ([]int, error)
}

View File

@@ -36,14 +36,15 @@ func (m *MockClient) EXPECT() *MockClientMockRecorder {
return m.recorder
}
// DetectFramework mocks base method.
func (m *MockClient) DetectFramework(ctx context.Context, path string) (model.DevFileType, api.Registry, error) {
// DetectFramework mocks base method
func (m *MockClient) DetectFramework(ctx context.Context, path string) (model.DevFileType, string, api.Registry, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "DetectFramework", ctx, path)
ret0, _ := ret[0].(model.DevFileType)
ret1, _ := ret[1].(api.Registry)
ret2, _ := ret[2].(error)
return ret0, ret1, ret2
ret1, _ := ret[1].(string)
ret2, _ := ret[2].(api.Registry)
ret3, _ := ret[3].(error)
return ret0, ret1, ret2, ret3
}
// DetectFramework indicates an expected call of DetectFramework.

View File

@@ -15,5 +15,6 @@ type DetectionResult struct {
DevfilePath string `json:"devfilePath,omitempty"`
// ApplicationPorts represents the list of ports detected
ApplicationPorts []int `json:"ports,omitempty"`
ApplicationPorts []int `json:"ports,omitempty"`
DevfileVersion string `json:"devfileVersion,omitempty"`
}

View File

@@ -3,6 +3,7 @@ package asker
import (
"fmt"
"sort"
"strings"
"github.com/AlecAivazis/survey/v2"
@@ -11,6 +12,10 @@ import (
"github.com/redhat-developer/odo/pkg/registry"
)
const (
GOBACK = "** GO BACK **"
)
type Survey struct{}
var _ Asker = (*Survey)(nil)
@@ -35,7 +40,7 @@ func (o *Survey) AskLanguage(langs []string) (string, error) {
func (o *Survey) AskType(types registry.TypesWithDetails) (back bool, _ api.DevfileStack, _ error) {
stringTypes := types.GetOrderedLabels()
stringTypes = append(stringTypes, "** GO BACK **")
stringTypes = append(stringTypes, GOBACK)
question := &survey.Select{
Message: "Select project type:",
Options: stringTypes,
@@ -52,6 +57,31 @@ func (o *Survey) AskType(types registry.TypesWithDetails) (back bool, _ api.Devf
return false, compType, err
}
func (o *Survey) AskVersion(versions []api.DevfileStackVersion) (back bool, version string, _ error) {
var stringVersions []string
for _, version := range versions {
sVersion := version.Version
if version.IsDefault {
sVersion += " (default)"
}
stringVersions = append(stringVersions, sVersion)
}
stringVersions = append(stringVersions, GOBACK)
question := &survey.Select{
Message: "Select version: ",
Options: stringVersions,
}
var answerPos int
err := survey.AskOne(question, &answerPos)
if err != nil {
return false, "", err
}
if answerPos == len(stringVersions)-1 {
return true, "", nil
}
return false, strings.ReplaceAll(stringVersions[answerPos], " (default)", ""), err
}
func (o *Survey) AskStarterProject(projects []string) (bool, int, error) {
projects = append(projects, "** NO STARTER PROJECT **")
question := &survey.Select{

View File

@@ -16,6 +16,10 @@ type Asker interface {
// or the selected type is returned
AskType(types registry.TypesWithDetails) (back bool, _ api.DevfileStack, _ error)
// AskVersion asks for the Devfile version, or to go back. back is returned as true if the user selected to go back,
// or the selected version is returned
AskVersion(versions []api.DevfileStackVersion) (back bool, version string, _ error)
// AskStarterProject asks for an optional project, from a list of projects. If no project is selected, false is returned.
// Or the index of the selected project is returned
AskStarterProject(projects []string) (selected bool, _ int, _ error)

View File

@@ -157,6 +157,22 @@ func (mr *MockAskerMockRecorder) AskStarterProject(projects interface{}) *gomock
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AskStarterProject", reflect.TypeOf((*MockAsker)(nil).AskStarterProject), projects)
}
// AskVersion mocks base method
func (m *MockAsker) AskVersion(versions []api.DevfileStackVersion) (bool, string, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "AskVersion", versions)
ret0, _ := ret[0].(bool)
ret1, _ := ret[1].(string)
ret2, _ := ret[2].(error)
return ret0, ret1, ret2
}
// AskVersion indicates an expected call of AskVersion
func (mr *MockAskerMockRecorder) AskVersion(versions interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AskVersion", reflect.TypeOf((*MockAsker)(nil).AskVersion), versions)
}
// AskType mocks base method.
func (m *MockAsker) AskType(types registry.TypesWithDetails) (bool, api.DevfileStack, error) {
m.ctrl.T.Helper()

View File

@@ -35,7 +35,7 @@ func (o *AlizerBackend) Validate(flags map[string]string, fs filesystem.Filesyst
// SelectDevfile calls thz Alizer to detect the devfile and asks for confirmation to the user
func (o *AlizerBackend) SelectDevfile(ctx context.Context, flags map[string]string, fs filesystem.Filesystem, dir string) (location *api.DetectionResult, err error) {
selected, registry, err := o.alizerClient.DetectFramework(ctx, dir)
selected, defaultVersion, registry, err := o.alizerClient.DetectFramework(ctx, dir)
if err != nil {
return nil, err
}
@@ -55,7 +55,7 @@ func (o *AlizerBackend) SelectDevfile(ctx context.Context, flags map[string]stri
}
fmt.Println(msg)
fmt.Printf("The devfile %q from the registry %q will be downloaded.\n", selected.Name, registry.Name)
fmt.Printf("The devfile \"%s:%s\" from the registry %q will be downloaded.\n", selected.Name, defaultVersion, registry.Name)
confirm, err := o.askerClient.AskCorrect()
if err != nil {
return nil, err
@@ -63,7 +63,7 @@ func (o *AlizerBackend) SelectDevfile(ctx context.Context, flags map[string]stri
if !confirm {
return nil, nil
}
return alizer.NewDetectionResult(selected, registry, appPorts), nil
return alizer.NewDetectionResult(selected, registry, appPorts, defaultVersion), nil
}
func (o *AlizerBackend) SelectStarterProject(devfile parser.DevfileObj, flags map[string]string) (starter *v1alpha2.StarterProject, err error) {

View File

@@ -54,7 +54,7 @@ func TestAlizerBackend_SelectDevfile(t *testing.T) {
alizerClient := alizer.NewMockClient(ctrl)
alizerClient.EXPECT().DetectFramework(gomock.Any(), gomock.Any()).Return(model.DevFileType{
Name: "a-devfile-name",
}, api.Registry{
}, "1.0.0", api.Registry{
Name: "a-registry",
}, errors.New("unable to detect framework"))
return alizerClient
@@ -78,7 +78,7 @@ func TestAlizerBackend_SelectDevfile(t *testing.T) {
alizerClient := alizer.NewMockClient(ctrl)
alizerClient.EXPECT().DetectFramework(gomock.Any(), gomock.Any()).Return(model.DevFileType{
Name: "a-devfile-name",
}, api.Registry{
}, "1.0.0", api.Registry{
Name: "a-registry",
}, nil)
alizerClient.EXPECT().DetectPorts(gomock.Any()).Return(nil, errors.New("unable to detect ports"))
@@ -103,7 +103,7 @@ func TestAlizerBackend_SelectDevfile(t *testing.T) {
alizerClient := alizer.NewMockClient(ctrl)
alizerClient.EXPECT().DetectFramework(gomock.Any(), gomock.Any()).Return(model.DevFileType{
Name: "a-devfile-name",
}, api.Registry{
}, "1.0.0", api.Registry{
Name: "a-registry",
}, nil)
alizerClient.EXPECT().DetectPorts(gomock.Any()).Return(nil, nil)
@@ -128,7 +128,7 @@ func TestAlizerBackend_SelectDevfile(t *testing.T) {
alizerClient := alizer.NewMockClient(ctrl)
alizerClient.EXPECT().DetectFramework(gomock.Any(), gomock.Any()).Return(model.DevFileType{
Name: "a-devfile-name",
}, api.Registry{
}, "1.0.0", api.Registry{
Name: "a-registry",
}, nil)
alizerClient.EXPECT().DetectPorts(gomock.Any()).Return(nil, nil)
@@ -142,6 +142,7 @@ func TestAlizerBackend_SelectDevfile(t *testing.T) {
wantLocation: &api.DetectionResult{
Devfile: "a-devfile-name",
DevfileRegistry: "a-registry",
DevfileVersion: "1.0.0",
},
},
{
@@ -154,7 +155,7 @@ func TestAlizerBackend_SelectDevfile(t *testing.T) {
},
alizerClient: func(ctrl *gomock.Controller) alizer.Client {
alizerClient := alizer.NewMockClient(ctrl)
alizerClient.EXPECT().DetectFramework(gomock.Any(), gomock.Any()).Return(model.DevFileType{}, api.Registry{}, nil)
alizerClient.EXPECT().DetectFramework(gomock.Any(), gomock.Any()).Return(model.DevFileType{}, "", api.Registry{}, nil)
alizerClient.EXPECT().DetectPorts(gomock.Any()).Return(nil, nil)
return alizerClient
},
@@ -177,7 +178,7 @@ func TestAlizerBackend_SelectDevfile(t *testing.T) {
alizerClient := alizer.NewMockClient(ctrl)
alizerClient.EXPECT().DetectFramework(gomock.Any(), gomock.Any()).Return(model.DevFileType{
Name: "a-devfile-name",
}, api.Registry{
}, "1.0.0", api.Registry{
Name: "a-registry",
}, nil)
alizerClient.EXPECT().DetectPorts(gomock.Any()).Return([]int{1234, 5678}, nil)
@@ -192,6 +193,7 @@ func TestAlizerBackend_SelectDevfile(t *testing.T) {
Devfile: "a-devfile-name",
DevfileRegistry: "a-registry",
ApplicationPorts: []int{1234, 5678},
DevfileVersion: "1.0.0",
},
},
// TODO: Add test cases.

View File

@@ -24,6 +24,7 @@ const (
FLAG_DEVFILE_REGISTRY = "devfile-registry"
FLAG_STARTER = "starter"
FLAG_DEVFILE_PATH = "devfile-path"
FLAG_DEVFILE_VERSION = "devfile-version"
)
// FlagsBackend is a backend that will extract all needed information from flags passed to the command
@@ -91,6 +92,7 @@ func (o *FlagsBackend) SelectDevfile(ctx context.Context, flags map[string]strin
Devfile: flags[FLAG_DEVFILE],
DevfileRegistry: flags[FLAG_DEVFILE_REGISTRY],
DevfilePath: flags[FLAG_DEVFILE_PATH],
DevfileVersion: flags[FLAG_DEVFILE_VERSION],
}, nil
}

View File

@@ -24,6 +24,7 @@ import (
const (
STATE_ASK_LANG = iota
STATE_ASK_TYPE
STATE_ASK_VERSION
STATE_END
)
@@ -81,6 +82,22 @@ loop:
}
result.DevfileRegistry = details.Registry.Name
result.Devfile = details.Name
if len(details.Versions) > 1 {
state = STATE_ASK_VERSION
} else {
state = STATE_END
}
case STATE_ASK_VERSION:
var back bool
back, version, err := o.askerClient.AskVersion(details.Versions)
if err != nil {
return nil, err
}
if back {
state = STATE_ASK_TYPE
continue loop
}
result.DevfileVersion = version
state = STATE_END
case STATE_END:
break loop

View File

@@ -58,7 +58,7 @@ func NewInitClient(fsys filesystem.Filesystem, preferenceClient preference.Clien
func (o *InitClient) GetFlags(flags map[string]string) map[string]string {
initFlags := map[string]string{}
for flag, value := range flags {
if flag == backend.FLAG_NAME || flag == backend.FLAG_DEVFILE || flag == backend.FLAG_DEVFILE_REGISTRY || flag == backend.FLAG_STARTER || flag == backend.FLAG_DEVFILE_PATH {
if flag == backend.FLAG_NAME || flag == backend.FLAG_DEVFILE || flag == backend.FLAG_DEVFILE_REGISTRY || flag == backend.FLAG_STARTER || flag == backend.FLAG_DEVFILE_PATH || flag == backend.FLAG_DEVFILE_VERSION {
initFlags[flag] = value
}
}
@@ -114,7 +114,11 @@ func (o *InitClient) DownloadDevfile(ctx context.Context, devfileLocation *api.D
if devfileLocation.DevfilePath != "" {
return destDevfile, o.downloadDirect(devfileLocation.DevfilePath, destDevfile)
} else {
return destDevfile, o.downloadFromRegistry(ctx, devfileLocation.DevfileRegistry, devfileLocation.Devfile, destDir)
devfile := devfileLocation.Devfile
if devfileLocation.DevfileVersion != "" {
devfile = fmt.Sprintf("%s:%s", devfileLocation.Devfile, devfileLocation.DevfileVersion)
}
return destDevfile, o.downloadFromRegistry(ctx, devfileLocation.DevfileRegistry, devfile, destDir)
}
}
@@ -163,6 +167,10 @@ func (o *InitClient) downloadDirect(URL string, dest string) error {
// downloadFromRegistry downloads a devfile from the provided registry and saves it in dest
// If registryName is empty, will try to download the devfile from the list of registries in preferences
func (o *InitClient) downloadFromRegistry(ctx context.Context, registryName string, devfile string, dest string) error {
// setting NewIndexSchema ensures that the Devfile library pulls registry based on the stack version
registryOptions := segment.GetRegistryOptions(ctx)
registryOptions.NewIndexSchema = true
var downloadSpinner *log.Status
var forceRegistry bool
if registryName == "" {
@@ -178,14 +186,14 @@ func (o *InitClient) downloadFromRegistry(ctx context.Context, registryName stri
var reg preference.Registry
for _, reg = range registries {
if forceRegistry && reg.Name == registryName {
err := o.registryClient.PullStackFromRegistry(reg.URL, devfile, dest, segment.GetRegistryOptions(ctx))
err := o.registryClient.PullStackFromRegistry(reg.URL, devfile, dest, registryOptions)
if err != nil {
return err
}
downloadSpinner.End(true)
return nil
} else if !forceRegistry {
err := o.registryClient.PullStackFromRegistry(reg.URL, devfile, dest, segment.GetRegistryOptions(ctx))
err := o.registryClient.PullStackFromRegistry(reg.URL, devfile, dest, registryOptions)
if err != nil {
continue
}

View File

@@ -50,7 +50,7 @@ func (o *AlizerOptions) Run(ctx context.Context) (err error) {
// RunForJsonOutput contains the logic for the odo command
func (o *AlizerOptions) RunForJsonOutput(ctx context.Context) (out interface{}, err error) {
workingDir := odocontext.GetWorkingDirectory(ctx)
df, reg, err := o.clientset.AlizerClient.DetectFramework(ctx, workingDir)
df, defaultVersion, reg, err := o.clientset.AlizerClient.DetectFramework(ctx, workingDir)
if err != nil {
return nil, err
}
@@ -58,7 +58,7 @@ func (o *AlizerOptions) RunForJsonOutput(ctx context.Context) (out interface{},
if err != nil {
return nil, err
}
result := alizer.NewDetectionResult(df, reg, appPorts)
result := alizer.NewDetectionResult(df, reg, appPorts, defaultVersion)
return []api.DetectionResult{*result}, nil
}

View File

@@ -43,9 +43,16 @@ var initExample = templates.Examples(`
# Boostrap a new component in interactive mode
%[1]s
# Bootstrap a new component with a specific devfile from registry
# Bootstrap a new component with a specific devfile from registry;
# if several versions of the devfile exists then it will download the default version
%[1]s --name my-app --devfile nodejs
# Bootstrap a new component with a specific versioned devfile from registry
%[1]s --name my-app --devfile nodejs --devfile-version 2.1.0
# Bootstrap a new component with the latest devfile from registry
%[1]s --name my-app --devfile nodejs --devfile-version latest
# Bootstrap a new component with a specific devfile from a specific registry
%[1]s --name my-app --devfile nodejs --devfile-registry MyRegistry
@@ -130,9 +137,13 @@ Changes will be directly reflected on the cluster.`, devfileObj.Data.GetMetadata
if len(o.flags) == 0 {
automateCommand := fmt.Sprintf("odo init --name %s --devfile %s --devfile-registry %s", name, devfileLocation.Devfile, devfileLocation.DevfileRegistry)
if devfileLocation.DevfileVersion != "" {
automateCommand = fmt.Sprintf("%s --devfile-version %s", automateCommand, devfileLocation.DevfileVersion)
}
if starterInfo != nil {
automateCommand = fmt.Sprintf("%s --starter %s", automateCommand, starterInfo.Name)
}
klog.V(2).Infof("Port configuration using flag is currently not supported")
log.Infof("\nYou can automate this command by executing:\n %s", automateCommand)
}
@@ -269,6 +280,7 @@ func NewCmdInit(name, fullName string) *cobra.Command {
initCmd.Flags().String(backend.FLAG_DEVFILE_REGISTRY, "", "name of the devfile registry (as configured in \"odo preference view\"). It can be used in combination with --devfile, but not with --devfile-path")
initCmd.Flags().String(backend.FLAG_STARTER, "", "name of the starter project")
initCmd.Flags().String(backend.FLAG_DEVFILE_PATH, "", "path to a devfile. This is an alternative to using devfile from Devfile registry. It can be local filesystem path or http(s) URL")
initCmd.Flags().String(backend.FLAG_DEVFILE_VERSION, "", "version of the devfile stack; use \"latest\" to dowload the latest stack")
commonflags.UseOutputFlag(initCmd)
// Add a defined annotation in order to appear in the help menu

View File

@@ -270,7 +270,8 @@ func (o RegistryClient) retrieveDevfileDataFromRegistry(ctx context.Context, reg
registries := o.preferenceClient.RegistryList()
var reg preference.Registry
registryOptions := segment.GetRegistryOptions(ctx)
registryOptions.NewIndexSchema = true
// Get the file and save it to the temporary file
// Why do we do that?
// 1. We need to get the file from the registry
@@ -279,7 +280,7 @@ func (o RegistryClient) retrieveDevfileDataFromRegistry(ctx context.Context, reg
// 4. We need to read the file from the temporary file, unmarshal it and then return the devfile data
for _, reg = range registries {
if reg.Name == registryName {
err = o.PullStackFromRegistry(reg.URL, devfileName, tmpFile, segment.GetRegistryOptions(ctx))
err = o.PullStackFromRegistry(reg.URL, devfileName, tmpFile, registryOptions)
if err != nil {
return api.DevfileData{}, err
}

View File

@@ -153,6 +153,52 @@ var _ = Describe("odo devfile init command tests", func() {
helper.JsonPathContentIs(stdout, "managedBy", "odo")
})
})
for _, ctx := range []struct {
title, devfileVersion, requiredVersion string
}{
{
title: "to download the latest version",
devfileVersion: "latest",
requiredVersion: "2.0.0",
},
{
title: "to download a specific version",
devfileVersion: "1.0.2",
requiredVersion: "1.0.2",
},
} {
ctx := ctx
const (
devfileName = "go"
)
When(fmt.Sprintf("using --devfile-version flag %s", ctx.title), func() {
BeforeEach(func() {
helper.Cmd("odo", "init", "--name", "aname", "--devfile", devfileName, "--devfile-version", ctx.devfileVersion).ShouldPass()
})
It("should download the devfile with the requested version", func() {
files := helper.ListFilesInDir(commonVar.Context)
Expect(files).To(ContainElements("devfile.yaml"))
metadata := helper.GetMetadataFromDevfile(filepath.Join(commonVar.Context, "devfile.yaml"))
Expect(metadata.Version).To(BeEquivalentTo(ctx.requiredVersion))
})
})
When(fmt.Sprintf("using --devfile-version flag and JSON output %s", ctx.title), func() {
var res *helper.CmdWrapper
BeforeEach(func() {
res = helper.Cmd("odo", "init", "--name", "aname", "--devfile", devfileName, "--devfile-version", ctx.devfileVersion, "-o", "json").ShouldPass()
})
It("should show the requested devfile version", func() {
stdout := res.Out()
Expect(helper.IsJSON(stdout)).To(BeTrue())
helper.JsonPathContentIs(stdout, "devfileData.devfile.metadata.version", ctx.requiredVersion)
})
})
}
When("using --devfile-path flag with a local devfile", func() {
var newContext string
BeforeEach(func() {

View File

@@ -41,7 +41,8 @@ var _ = Describe("odo deploy interactive command tests", func() {
language := "Python"
projectType := "Python"
devfileName := "python"
versionedDevfileName := "python:2.1.0"
output, err := helper.RunInteractive([]string{"odo", "deploy", "-v", "4"},
nil,
func(ctx helper.InteractiveContext) {
@@ -52,7 +53,7 @@ var _ = Describe("odo deploy interactive command tests", func() {
helper.ExpectString(ctx, fmt.Sprintf("Project type: %s", projectType))
helper.ExpectString(ctx,
fmt.Sprintf("The devfile \"%s\" from the registry \"DefaultDevfileRegistry\" will be downloaded.", devfileName))
fmt.Sprintf("The devfile %q from the registry \"DefaultDevfileRegistry\" will be downloaded.", versionedDevfileName))
helper.ExpectString(ctx, "Is this correct")
helper.SendLine(ctx, "")
@@ -75,7 +76,7 @@ var _ = Describe("odo deploy interactive command tests", func() {
language := "Python"
projectType := "Python"
devfileName := "python"
versionedDevfileName := "python:2.1.0"
output, err := helper.RunInteractive([]string{"odo", "deploy"},
nil,
func(ctx helper.InteractiveContext) {
@@ -86,7 +87,7 @@ var _ = Describe("odo deploy interactive command tests", func() {
helper.ExpectString(ctx, fmt.Sprintf("Project type: %s", projectType))
helper.ExpectString(ctx,
fmt.Sprintf("The devfile \"%s\" from the registry \"DefaultDevfileRegistry\" will be downloaded.", devfileName))
fmt.Sprintf("The devfile %q from the registry \"DefaultDevfileRegistry\" will be downloaded.", versionedDevfileName))
helper.ExpectString(ctx, "Is this correct")
helper.SendLine(ctx, "")
@@ -113,7 +114,7 @@ var _ = Describe("odo deploy interactive command tests", func() {
language := "Python"
projectType := "Python"
devfileName := "python"
versionedDevfileName := "python:2.1.0"
output, err := helper.RunInteractive([]string{"odo", "deploy"},
// Setting verbosity level to 0, because we would be asserting the welcoming message is the first
// message displayed to the end user. So we do not want any potential debug lines to be printed first.
@@ -127,7 +128,7 @@ var _ = Describe("odo deploy interactive command tests", func() {
helper.ExpectString(ctx, fmt.Sprintf("Project type: %s", projectType))
helper.ExpectString(ctx,
fmt.Sprintf("The devfile \"%s\" from the registry \"DefaultDevfileRegistry\" will be downloaded.", devfileName))
fmt.Sprintf("The devfile %q from the registry \"DefaultDevfileRegistry\" will be downloaded.", versionedDevfileName))
helper.ExpectString(ctx, "Is this correct")
helper.SendLine(ctx, "")

View File

@@ -41,7 +41,7 @@ var _ = Describe("odo dev interactive command tests", func() {
language := "Python"
projectType := "Python"
devfileName := "python"
versionedDevfileName := "python:2.1.0"
_, _ = helper.RunInteractive([]string{"odo", "dev", "--random-ports", "-v", "4"},
nil,
func(ctx helper.InteractiveContext) {
@@ -52,7 +52,7 @@ var _ = Describe("odo dev interactive command tests", func() {
helper.ExpectString(ctx, fmt.Sprintf("Project type: %s", projectType))
helper.ExpectString(ctx,
fmt.Sprintf("The devfile %q from the registry \"DefaultDevfileRegistry\" will be downloaded.", devfileName))
fmt.Sprintf("The devfile %q from the registry \"DefaultDevfileRegistry\" will be downloaded.", versionedDevfileName))
helper.ExpectString(ctx, "Is this correct")
helper.SendLine(ctx, "")
@@ -74,7 +74,7 @@ var _ = Describe("odo dev interactive command tests", func() {
language := "Python"
projectType := "Python"
devfileName := "python"
versionedDevfileName := "python:2.1.0"
_, _ = helper.RunInteractive([]string{"odo", "dev", "--random-ports"},
nil,
func(ctx helper.InteractiveContext) {
@@ -85,7 +85,7 @@ var _ = Describe("odo dev interactive command tests", func() {
helper.ExpectString(ctx, fmt.Sprintf("Project type: %s", projectType))
helper.ExpectString(ctx,
fmt.Sprintf("The devfile %q from the registry \"DefaultDevfileRegistry\" will be downloaded.", devfileName))
fmt.Sprintf("The devfile %q from the registry \"DefaultDevfileRegistry\" will be downloaded.", versionedDevfileName))
helper.ExpectString(ctx, "Is this correct")
helper.SendLine(ctx, "")
@@ -111,7 +111,7 @@ var _ = Describe("odo dev interactive command tests", func() {
language := "Python"
projectType := "Python"
devfileName := "python"
versionedDevfileName := "python:2.1.0"
output, _ := helper.RunInteractive([]string{"odo", "dev", "--random-ports"},
// Setting verbosity level to 0, because we would be asserting the welcoming message is the first
// message displayed to the end user. So we do not want any potential debug lines to be printed first.
@@ -125,7 +125,7 @@ var _ = Describe("odo dev interactive command tests", func() {
helper.ExpectString(ctx, fmt.Sprintf("Project type: %s", projectType))
helper.ExpectString(ctx,
fmt.Sprintf("The devfile %q from the registry \"DefaultDevfileRegistry\" will be downloaded.", devfileName))
fmt.Sprintf("The devfile %q from the registry \"DefaultDevfileRegistry\" will be downloaded.", versionedDevfileName))
helper.ExpectString(ctx, "Is this correct")
helper.SendLine(ctx, "")
@@ -160,6 +160,9 @@ var _ = Describe("odo dev interactive command tests", func() {
helper.SendLine(ctx, "Python")
helper.ExpectString(ctx, "Select project type")
helper.SendLine(ctx, "Python")
helper.ExpectString(ctx, "Select version")
helper.SendLine(ctx, "")
helper.ExpectString(ctx, "Select container for which you want to change configuration?")

View File

@@ -61,6 +61,9 @@ var _ = Describe("odo init interactive command tests", func() {
helper.ExpectString(ctx, "Select project type")
helper.SendLine(ctx, "")
helper.ExpectString(ctx, "Select version")
helper.SendLine(ctx, "")
helper.ExpectString(ctx, "Select container for which you want to change configuration?")
helper.SendLine(ctx, "")
@@ -88,6 +91,9 @@ var _ = Describe("odo init interactive command tests", func() {
helper.ExpectString(ctx, "Select project type")
helper.SendLine(ctx, "")
helper.ExpectString(ctx, "Select version")
helper.SendLine(ctx, "")
helper.ExpectString(ctx, "Select container for which you want to change configuration?")
helper.SendLine(ctx, "")
@@ -119,6 +125,7 @@ var _ = Describe("odo init interactive command tests", func() {
starter := "go-starter"
componentName := "my-go-app"
devfileName := "go"
devfileVersion := "1.0.2"
output, err := helper.RunInteractive(command, nil, func(ctx helper.InteractiveContext) {
@@ -128,6 +135,9 @@ var _ = Describe("odo init interactive command tests", func() {
helper.ExpectString(ctx, "Select project type")
helper.SendLine(ctx, "")
helper.ExpectString(ctx, "Select version")
helper.SendLine(ctx, "")
helper.ExpectString(ctx, "Select container for which you want to change configuration?")
helper.SendLine(ctx, "")
@@ -142,7 +152,7 @@ var _ = Describe("odo init interactive command tests", func() {
})
Expect(err).To(BeNil())
Expect(output).To(ContainSubstring("odo init --name %s --devfile %s --devfile-registry DefaultDevfileRegistry --starter %s", componentName, devfileName, starter))
Expect(output).To(ContainSubstring("odo init --name %s --devfile %s --devfile-registry DefaultDevfileRegistry --devfile-version %s --starter %s", componentName, devfileName, devfileVersion, starter))
Expect(output).To(ContainSubstring("Your new component 'my-go-app' is ready in the current directory"))
Expect(helper.ListFilesInDir(commonVar.Context)).To(ContainElements("devfile.yaml"))
})
@@ -162,6 +172,9 @@ var _ = Describe("odo init interactive command tests", func() {
helper.ExpectString(ctx, "Select project type")
helper.SendLine(ctx, "")
helper.ExpectString(ctx, "Select version")
helper.SendLine(ctx, "")
helper.ExpectString(ctx, "Select container for which you want to change configuration?")
helper.SendLine(ctx, "")
@@ -318,7 +331,7 @@ var _ = Describe("odo init interactive command tests", func() {
language := "Python"
projectType := "Python"
devfileName := "python"
versionedDevfileName := "python:2.1.0"
welcomingMsgs := strings.Split(odolog.Stitle(messages.InitializingNewComponent, messages.SourceCodeDetected, "odo version: "+version.VERSION), "\n")
output, err := testRunner(language, welcomingMsgs, func(ctx helper.InteractiveContext) {
@@ -329,7 +342,7 @@ var _ = Describe("odo init interactive command tests", func() {
helper.ExpectString(ctx, fmt.Sprintf("Project type: %s", projectType))
helper.ExpectString(ctx,
fmt.Sprintf("The devfile \"%s\" from the registry \"DefaultDevfileRegistry\" will be downloaded.", devfileName))
fmt.Sprintf("The devfile %q from the registry \"DefaultDevfileRegistry\" will be downloaded.", versionedDevfileName))
helper.ExpectString(ctx, "Is this correct")
helper.SendLine(ctx, "")
@@ -362,7 +375,7 @@ var _ = Describe("odo init interactive command tests", func() {
language := "JavaScript"
projectType := "Node.js"
projectName := "node-echo"
devfileName := "nodejs"
versionedDevfileName := "nodejs:2.1.1"
output, err := helper.RunInteractive([]string{"odo", "init"}, nil, func(ctx helper.InteractiveContext) {
helper.ExpectString(ctx, "Based on the files in the current directory odo detected")
@@ -372,7 +385,7 @@ var _ = Describe("odo init interactive command tests", func() {
helper.ExpectString(ctx, fmt.Sprintf("Project type: %s", projectType))
helper.ExpectString(ctx,
fmt.Sprintf("The devfile \"%s\" from the registry \"DefaultDevfileRegistry\" will be downloaded.", devfileName))
fmt.Sprintf("The devfile %q from the registry \"DefaultDevfileRegistry\" will be downloaded.", versionedDevfileName))
helper.ExpectString(ctx, "Is this correct")
helper.SendLine(ctx, "")
@@ -397,7 +410,7 @@ var _ = Describe("odo init interactive command tests", func() {
language := "JavaScript"
projectType := "Node.js"
projectName := "node-echo"
devfileName := "nodejs"
versionedDevfileName := "nodejs:2.1.1"
_, err := helper.RunInteractive([]string{"odo", "init"}, nil, func(ctx helper.InteractiveContext) {
helper.ExpectString(ctx, "Based on the files in the current directory odo detected")
@@ -407,7 +420,7 @@ var _ = Describe("odo init interactive command tests", func() {
helper.ExpectString(ctx, fmt.Sprintf("Project type: %s", projectType))
helper.ExpectString(ctx,
fmt.Sprintf("The devfile \"%s\" from the registry \"DefaultDevfileRegistry\" will be downloaded.", devfileName))
fmt.Sprintf("The devfile %q from the registry \"DefaultDevfileRegistry\" will be downloaded.", versionedDevfileName))
helper.ExpectString(ctx, "Is this correct")
helper.SendLine(ctx, "")