diff --git a/pkg/init/init.go b/pkg/init/init.go index 0e97367cb1a..0433aaa4789 100644 --- a/pkg/init/init.go +++ b/pkg/init/init.go @@ -254,27 +254,27 @@ func (o InitClient) PersonalizeDevfileConfig(devfileobj parser.DevfileObj, flags return backend.PersonalizeDevfileConfig(devfileobj) } -func (o InitClient) SelectAndPersonalizeDevfile(flags map[string]string, contextDir string) (parser.DevfileObj, string, error) { +func (o InitClient) SelectAndPersonalizeDevfile(flags map[string]string, contextDir string) (parser.DevfileObj, string, *api.DevfileLocation, error) { devfileLocation, err := o.SelectDevfile(flags, o.fsys, contextDir) if err != nil { - return parser.DevfileObj{}, "", err + return parser.DevfileObj{}, "", nil, err } devfilePath, err := o.DownloadDevfile(devfileLocation, contextDir) if err != nil { - return parser.DevfileObj{}, "", fmt.Errorf("unable to download devfile: %w", err) + return parser.DevfileObj{}, "", nil, fmt.Errorf("unable to download devfile: %w", err) } devfileObj, _, err := devfile.ParseDevfileAndValidate(parser.ParserArgs{Path: devfilePath, FlattenedDevfile: pointer.BoolPtr(false)}) if err != nil { - return parser.DevfileObj{}, "", fmt.Errorf("unable to parse devfile: %w", err) + return parser.DevfileObj{}, "", nil, fmt.Errorf("unable to parse devfile: %w", err) } devfileObj, err = o.PersonalizeDevfileConfig(devfileObj, flags, o.fsys, contextDir) if err != nil { - return parser.DevfileObj{}, "", fmt.Errorf("failed to configure devfile: %w", err) + return parser.DevfileObj{}, "", nil, fmt.Errorf("failed to configure devfile: %w", err) } - return devfileObj, devfilePath, nil + return devfileObj, devfilePath, devfileLocation, nil } func (o InitClient) InitDevfile(flags map[string]string, contextDir string, @@ -292,7 +292,7 @@ func (o InitClient) InitDevfile(flags map[string]string, contextDir string, preInitHandlerFunc(len(flags) == 0) } - devfileObj, _, err := o.SelectAndPersonalizeDevfile(map[string]string{}, contextDir) + devfileObj, _, _, err := o.SelectAndPersonalizeDevfile(map[string]string{}, contextDir) if err != nil { return err } diff --git a/pkg/init/interface.go b/pkg/init/interface.go index 0b0b9df415b..8a0ed64e1cc 100644 --- a/pkg/init/interface.go +++ b/pkg/init/interface.go @@ -57,6 +57,6 @@ type Client interface { PersonalizeDevfileConfig(devfileobj parser.DevfileObj, flags map[string]string, fs filesystem.Filesystem, dir string) (parser.DevfileObj, error) // SelectAndPersonalizeDevfile selects a devfile, then downloads, parse and personalize it - // Returns the devfile object and its path - SelectAndPersonalizeDevfile(flags map[string]string, contextDir string) (parser.DevfileObj, string, error) + // Returns the devfile object, its path and pointer to *api.devfileLocation + SelectAndPersonalizeDevfile(flags map[string]string, contextDir string) (parser.DevfileObj, string, *api.DevfileLocation, error) } diff --git a/pkg/init/mock.go b/pkg/init/mock.go index 6fcb8f24362..208d7443cdf 100644 --- a/pkg/init/mock.go +++ b/pkg/init/mock.go @@ -125,13 +125,14 @@ func (mr *MockClientMockRecorder) PersonalizeName(devfile, flags interface{}) *g } // SelectAndPersonalizeDevfile mocks base method. -func (m *MockClient) SelectAndPersonalizeDevfile(flags map[string]string, contextDir string) (parser.DevfileObj, string, error) { +func (m *MockClient) SelectAndPersonalizeDevfile(flags map[string]string, contextDir string) (parser.DevfileObj, string, *api.DevfileLocation, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "SelectAndPersonalizeDevfile", flags, contextDir) ret0, _ := ret[0].(parser.DevfileObj) ret1, _ := ret[1].(string) - ret2, _ := ret[2].(error) - return ret0, ret1, ret2 + ret2, _ := ret[2].(*api.DevfileLocation) + ret3, _ := ret[3].(error) + return ret0, ret1, ret2, ret3 } // SelectAndPersonalizeDevfile indicates an expected call of SelectAndPersonalizeDevfile. diff --git a/pkg/odo/cli/init/init.go b/pkg/odo/cli/init/init.go index 086884f7636..fe427a43da6 100644 --- a/pkg/odo/cli/init/init.go +++ b/pkg/odo/cli/init/init.go @@ -7,6 +7,7 @@ import ( "github.com/spf13/cobra" + "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2" "github.com/devfile/library/pkg/devfile" "github.com/devfile/library/pkg/devfile/parser" @@ -113,7 +114,7 @@ func (o *InitOptions) Validate(ctx context.Context) error { // Run contains the logic for the odo command func (o *InitOptions) Run(ctx context.Context) (err error) { - devfileObj, _, err := o.run(ctx) + devfileObj, _, name, devfileLocation, starterInfo, err := o.run(ctx) if err != nil { return err } @@ -123,6 +124,14 @@ Your new component '%s' 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.`, devfileObj.Data.GetMetadata().Name) + if len(o.flags) == 0 { + automateCommad := fmt.Sprintf("odo init --name %s --devfile %s --devfile-registry %s", name, devfileLocation.Devfile, devfileLocation.DevfileRegistry) + if starterInfo != nil { + automateCommad = fmt.Sprintf("%s --starter %s", automateCommad, starterInfo.Name) + } + log.Infof("\nPort configuration using flag is currently not supported \n\nYou can automate this command by executing:\n %s\n", automateCommad) + } + if libdevfile.HasDeployCommand(devfileObj.Data) { exitMessage += "\nTo deploy your component to a cluster use \"odo deploy\"." } @@ -133,7 +142,7 @@ Changes will be directly reflected on the cluster.`, devfileObj.Data.GetMetadata // RunForJsonOutput is executed instead of Run when -o json flag is given func (o *InitOptions) RunForJsonOutput(ctx context.Context) (out interface{}, err error) { - devfileObj, devfilePath, err := o.run(ctx) + devfileObj, devfilePath, _, _, _, err := o.run(ctx) if err != nil { return nil, err } @@ -146,8 +155,8 @@ func (o *InitOptions) RunForJsonOutput(ctx context.Context) (out interface{}, er }, nil } -// run downloads the devfile and starter project and returns the content and the path of the devfile -func (o *InitOptions) run(ctx context.Context) (devfileObj parser.DevfileObj, path string, err error) { +// run downloads the devfile and starter project and returns the content of the devfile, path of the devfile, name of the component, api.DevfileLocation object for DevfileRegistry info and StarterProject object +func (o *InitOptions) run(ctx context.Context) (devfileObj parser.DevfileObj, path string, name string, devfileLocation *api.DevfileLocation, starterInfo *v1alpha2.StarterProject, err error) { var starterDownloaded bool workingDir := odocontext.GetWorkingDirectory(ctx) @@ -166,7 +175,7 @@ func (o *InitOptions) run(ctx context.Context) (devfileObj parser.DevfileObj, pa isEmptyDir, err := location.DirIsEmpty(o.clientset.FS, workingDir) if err != nil { - return parser.DevfileObj{}, "", err + return parser.DevfileObj{}, "", "", nil, nil, err } // Show a welcome message for when you initially run `odo init`. @@ -183,28 +192,28 @@ func (o *InitOptions) run(ctx context.Context) (devfileObj parser.DevfileObj, pa log.Info(messages.InteractiveModeEnabled) } - devfileObj, devfilePath, err := o.clientset.InitClient.SelectAndPersonalizeDevfile(o.flags, workingDir) + devfileObj, devfilePath, devfileLocation, err := o.clientset.InitClient.SelectAndPersonalizeDevfile(o.flags, workingDir) if err != nil { - return parser.DevfileObj{}, "", err + return parser.DevfileObj{}, "", "", nil, nil, err } - starterInfo, err := o.clientset.InitClient.SelectStarterProject(devfileObj, o.flags, o.clientset.FS, workingDir) + starterInfo, err = o.clientset.InitClient.SelectStarterProject(devfileObj, o.flags, o.clientset.FS, workingDir) if err != nil { - return parser.DevfileObj{}, "", err + return parser.DevfileObj{}, "", "", nil, nil, err } // Set the name in the devfile but do not write it yet to disk, // because the starter project downloaded at the end might come bundled with a specific Devfile. - name, err := o.clientset.InitClient.PersonalizeName(devfileObj, o.flags) + name, err = o.clientset.InitClient.PersonalizeName(devfileObj, o.flags) if err != nil { - return parser.DevfileObj{}, "", fmt.Errorf("failed to update the devfile's name: %w", err) + return parser.DevfileObj{}, "", "", nil, nil, fmt.Errorf("failed to update the devfile's name: %w", err) } if starterInfo != nil { // WARNING: this will remove all the content of the destination directory, ie the devfile.yaml file err = o.clientset.InitClient.DownloadStarterProject(starterInfo, workingDir) if err != nil { - return parser.DevfileObj{}, "", fmt.Errorf("unable to download starter project %q: %w", starterInfo.Name, err) + return parser.DevfileObj{}, "", "", nil, nil, fmt.Errorf("unable to download starter project %q: %w", starterInfo.Name, err) } starterDownloaded = true @@ -212,20 +221,20 @@ func (o *InitOptions) run(ctx context.Context) (devfileObj parser.DevfileObj, pa if _, err = o.clientset.FS.Stat(devfilePath); err == nil { devfileObj, _, err = devfile.ParseDevfileAndValidate(parser.ParserArgs{Path: devfilePath, FlattenedDevfile: pointer.BoolPtr(false)}) if err != nil { - return parser.DevfileObj{}, "", err + return parser.DevfileObj{}, "", "", nil, nil, err } } } // WARNING: SetMetadataName writes the Devfile to disk if err = devfileObj.SetMetadataName(name); err != nil { - return parser.DevfileObj{}, "", err + return parser.DevfileObj{}, "", "", nil, nil, err } scontext.SetComponentType(ctx, component.GetComponentTypeFromDevfileMetadata(devfileObj.Data.GetMetadata())) scontext.SetLanguage(ctx, devfileObj.Data.GetMetadata().Language) scontext.SetProjectType(ctx, devfileObj.Data.GetMetadata().ProjectType) scontext.SetDevfileName(ctx, devfileObj.GetMetadataName()) - return devfileObj, devfilePath, nil + return devfileObj, devfilePath, name, devfileLocation, starterInfo, nil } // NewCmdInit implements the odo command diff --git a/tests/integration/interactive_init_test.go b/tests/integration/interactive_init_test.go index 7e1cf4a33eb..37fb02c8fae 100644 --- a/tests/integration/interactive_init_test.go +++ b/tests/integration/interactive_init_test.go @@ -92,6 +92,36 @@ var _ = Describe("odo init interactive command tests", Label(helper.LabelNoClust Expect(helper.ListFilesInDir(commonVar.Context)).To(ContainElements("devfile.yaml")) }) + It("should print automation command with proper values", func() { + command := []string{"odo", "init"} + starter := "go-starter" + componentName := "my-go-app" + devfileName := "go" + + output, err := helper.RunInteractive(command, nil, func(ctx helper.InteractiveContext) { + + helper.ExpectString(ctx, "Select language") + helper.SendLine(ctx, "Go") + + helper.ExpectString(ctx, "Select project type") + helper.SendLine(ctx, "") + + helper.ExpectString(ctx, "Which starter project do you want to use") + helper.SendLine(ctx, starter) + + helper.ExpectString(ctx, "Enter component name") + helper.SendLine(ctx, componentName) + + helper.ExpectString(ctx, "Your new component 'my-go-app' is ready in the current directory") + + }) + + 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("Your new component 'my-go-app' is ready in the current directory")) + Expect(helper.ListFilesInDir(commonVar.Context)).To(ContainElements("devfile.yaml")) + }) + It("should download correct devfile", func() { command := []string{"odo", "init"}