From 2c6c9f1a418c6620026a1d9908f268083a706e35 Mon Sep 17 00:00:00 2001 From: Armel Soro Date: Fri, 18 Mar 2022 12:58:39 +0100 Subject: [PATCH] Make dev and deploy subcommands display welcoming messages too (#5556) This relates to [1], because users might have similar symptoms (few seconds before any output) when running either `odo dev` or `odo deploy` in a source code directory with no Devfile, and those commands try to do an Alizer analysis first. [1] https://github.com/redhat-developer/odo/issues/5494 --- pkg/init/init.go | 24 +++++++++++++++++ pkg/init/interface.go | 6 +++++ pkg/init/mock.go | 14 ++++++++++ pkg/odo/cli/deploy/deploy.go | 30 +++++---------------- pkg/odo/cli/dev/dev.go | 30 +++++---------------- tests/interactive/cmd_deploy_test.go | 39 ++++++++++++++++++++++++++++ tests/interactive/cmd_dev_test.go | 38 +++++++++++++++++++++++++++ 7 files changed, 133 insertions(+), 48 deletions(-) diff --git a/pkg/init/init.go b/pkg/init/init.go index aa2ab650eb4..6e765db0fcc 100644 --- a/pkg/init/init.go +++ b/pkg/init/init.go @@ -263,3 +263,27 @@ func (o InitClient) SelectAndPersonalizeDevfile(flags map[string]string, context } return devfileObj, devfilePath, nil } + +func (o InitClient) InitDevfile(flags map[string]string, contextDir string, preInitHandlerFunc func(interactiveMode bool)) error { + containsDevfile, err := location.DirectoryContainsDevfile(o.fsys, contextDir) + if err != nil { + return err + } + if containsDevfile { + return nil + } + + preInitHandlerFunc(len(flags) == 0) + + devfileObj, _, err := o.SelectAndPersonalizeDevfile(map[string]string{}, contextDir) + if err != nil { + return err + } + + // Set the name in the devfile and writes the devfile back to the disk + err = o.PersonalizeName(devfileObj, map[string]string{}) + if err != nil { + return fmt.Errorf("failed to update the devfile's name: %w", err) + } + return nil +} diff --git a/pkg/init/interface.go b/pkg/init/interface.go index 62228ad9172..d037940e956 100644 --- a/pkg/init/interface.go +++ b/pkg/init/interface.go @@ -19,6 +19,12 @@ type Client interface { // Validate checks for each backend if flags are valid Validate(flags map[string]string, fs filesystem.Filesystem, dir string) error + // InitDevfile allows to initialize a Devfile in cases where this operation is needed as a prerequisite, + // like if the directory contains no Devfile at all. + // `preInitHandlerFunc` allows to perform operations prior to triggering the actual Devfile + // initialization and personalization process. + InitDevfile(flags map[string]string, contextDir string, preInitHandlerFunc func(interactiveMode bool)) error + // SelectDevfile returns information about a devfile selected based on Alizer if the directory content, // or based on the flags if the directory is empty, or // interactively if flags is empty diff --git a/pkg/init/mock.go b/pkg/init/mock.go index 814bfac0469..017a48535b2 100644 --- a/pkg/init/mock.go +++ b/pkg/init/mock.go @@ -66,6 +66,20 @@ func (mr *MockClientMockRecorder) DownloadStarterProject(project, dest interface return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DownloadStarterProject", reflect.TypeOf((*MockClient)(nil).DownloadStarterProject), project, dest) } +// InitDevfile mocks base method. +func (m *MockClient) InitDevfile(flags map[string]string, contextDir string, preInitHandlerFunc func(bool)) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InitDevfile", flags, contextDir, preInitHandlerFunc) + ret0, _ := ret[0].(error) + return ret0 +} + +// InitDevfile indicates an expected call of InitDevfile. +func (mr *MockClientMockRecorder) InitDevfile(flags, contextDir, preInitHandlerFunc interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InitDevfile", reflect.TypeOf((*MockClient)(nil).InitDevfile), flags, contextDir, preInitHandlerFunc) +} + // PersonalizeDevfileConfig mocks base method. func (m *MockClient) PersonalizeDevfileConfig(devfileobj parser.DevfileObj, flags map[string]string, fs filesystem.Filesystem, dir string) error { m.ctrl.T.Helper() diff --git a/pkg/odo/cli/deploy/deploy.go b/pkg/odo/cli/deploy/deploy.go index 2ec50080699..6c1e95966bf 100644 --- a/pkg/odo/cli/deploy/deploy.go +++ b/pkg/odo/cli/deploy/deploy.go @@ -15,8 +15,6 @@ import ( "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/testingutil/filesystem" - "k8s.io/kubectl/pkg/util/templates" ) @@ -64,7 +62,12 @@ func (o *DeployOptions) Complete(cmdline cmdline.Cmdline, args []string) (err er return errors.New("this command cannot run in an empty directory, you need to run it in a directory containing source code") } - err = o.initDevfile() + err = o.clientset.InitClient.InitDevfile(cmdline.GetFlags(), o.contextDir, func(interactiveMode bool) { + if interactiveMode { + fmt.Println("The current directory already contains source code. " + + "odo will try to autodetect the language and project type in order to select the best suited Devfile for your project.") + } + }) if err != nil { return err } @@ -105,27 +108,6 @@ func (o *DeployOptions) Validate() error { return nil } -func (o *DeployOptions) initDevfile() error { - containsDevfile, err := location.DirectoryContainsDevfile(filesystem.DefaultFs{}, o.contextDir) - if err != nil { - return err - } - if containsDevfile { - return nil - } - devfileObj, _, err := o.clientset.InitClient.SelectAndPersonalizeDevfile(map[string]string{}, o.contextDir) - if err != nil { - return err - } - - // Set the name in the devfile and writes the devfile back to the disk - err = o.clientset.InitClient.PersonalizeName(devfileObj, map[string]string{}) - if err != nil { - return fmt.Errorf("failed to update the devfile's name: %w", err) - } - return nil -} - // Run contains the logic for the odo command func (o *DeployOptions) Run() error { devfileObj := o.EnvSpecificInfo.GetDevfileObj() diff --git a/pkg/odo/cli/dev/dev.go b/pkg/odo/cli/dev/dev.go index e5f7b74ed14..e55ce36d165 100644 --- a/pkg/odo/cli/dev/dev.go +++ b/pkg/odo/cli/dev/dev.go @@ -10,7 +10,6 @@ import ( "github.com/redhat-developer/odo/pkg/devfile/adapters" "github.com/redhat-developer/odo/pkg/devfile/adapters/common" "github.com/redhat-developer/odo/pkg/devfile/location" - "github.com/redhat-developer/odo/pkg/testingutil/filesystem" "github.com/redhat-developer/odo/pkg/watch" dfutil "github.com/devfile/library/pkg/util" @@ -81,7 +80,12 @@ func (o *DevOptions) Complete(cmdline cmdline.Cmdline, args []string) error { return errors.New("this command cannot run in an empty directory, you need to run it in a directory containing source code") } - err = o.initDevfile() + err = o.clientset.InitClient.InitDevfile(cmdline.GetFlags(), o.contextDir, func(interactiveMode bool) { + if interactiveMode { + fmt.Println("The current directory already contains source code. " + + "odo will try to autodetect the language and project type in order to select the best suited Devfile for your project.") + } + }) if err != nil { return err } @@ -141,28 +145,6 @@ func (o *DevOptions) Validate() error { return err } -func (o *DevOptions) initDevfile() error { - containsDevfile, err := location.DirectoryContainsDevfile(filesystem.DefaultFs{}, o.contextDir) - if err != nil { - return err - } - if containsDevfile { - return nil - } - - devfileObj, _, err := o.clientset.InitClient.SelectAndPersonalizeDevfile(map[string]string{}, o.contextDir) - if err != nil { - return err - } - - // Set the name in the devfile and writes the devfile back to the disk - err = o.clientset.InitClient.PersonalizeName(devfileObj, map[string]string{}) - if err != nil { - return fmt.Errorf("failed to update the devfile's name: %w", err) - } - return nil -} - func (o *DevOptions) Run() error { var err error var platformContext = kubernetes.KubernetesContext{ diff --git a/tests/interactive/cmd_deploy_test.go b/tests/interactive/cmd_deploy_test.go index 40aeb8aa697..6f9ee9689f2 100644 --- a/tests/interactive/cmd_deploy_test.go +++ b/tests/interactive/cmd_deploy_test.go @@ -69,5 +69,44 @@ var _ = Describe("odo deploy interactive command tests", func() { Expect(output).To(ContainSubstring("no deploy command found in devfile")) Expect(helper.ListFilesInDir(commonVar.Context)).To(ContainElements("devfile.yaml")) }) + + It("should display welcoming messages first", func() { + + language := "python" + 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. + // Using envvars here (and not via the -v flag), because of https://github.com/redhat-developer/odo/issues/5513 + []string{"ODO_LOG_LEVEL=0"}, + func(ctx helper.InteractiveContext) { + helper.ExpectString(ctx, "Based on the files in the current directory odo detected") + + helper.ExpectString(ctx, fmt.Sprintf("Language: %s", language)) + + helper.ExpectString(ctx, fmt.Sprintf("Project type: %s", language)) + + helper.ExpectString(ctx, + fmt.Sprintf("The devfile \"%s\" from the registry \"DefaultDevfileRegistry\" will be downloaded.", language)) + + helper.ExpectString(ctx, "Is this correct") + helper.SendLine(ctx, "\n") + + helper.ExpectString(ctx, "Select container for which you want to change configuration") + helper.SendLine(ctx, "\n") + + helper.ExpectString(ctx, "Enter component name") + helper.SendLine(ctx, "my-app") + + helper.ExpectString(ctx, "no deploy command found in devfile") + }) + + Expect(err).To(Not(BeNil())) + // Make sure it also displays welcoming messages first + lines, err := helper.ExtractLines(output) + Expect(err).To(BeNil()) + Expect(lines).To(Not(BeEmpty())) + Expect(lines[0]).To(Equal("The current directory already contains source code. " + + "odo will try to autodetect the language and project type in order to select the best suited Devfile for your project.")) + }) }) }) diff --git a/tests/interactive/cmd_dev_test.go b/tests/interactive/cmd_dev_test.go index e78aef427f0..83f21ea8a78 100644 --- a/tests/interactive/cmd_dev_test.go +++ b/tests/interactive/cmd_dev_test.go @@ -68,5 +68,43 @@ var _ = Describe("odo dev interactive command tests", func() { Expect(helper.ListFilesInDir(commonVar.Context)).To(ContainElements("devfile.yaml")) }) + + It("should display welcoming messages first", func() { + + language := "python" + output, _ := helper.RunInteractive([]string{"odo", "dev"}, + // 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. + // Using envvars here (and not via the -v flag), because of https://github.com/redhat-developer/odo/issues/5513 + []string{"ODO_LOG_LEVEL=0"}, + func(ctx helper.InteractiveContext) { + helper.ExpectString(ctx, "Based on the files in the current directory odo detected") + + helper.ExpectString(ctx, fmt.Sprintf("Language: %s", language)) + + helper.ExpectString(ctx, fmt.Sprintf("Project type: %s", language)) + + helper.ExpectString(ctx, + fmt.Sprintf("The devfile %q from the registry \"DefaultDevfileRegistry\" will be downloaded.", language)) + + helper.ExpectString(ctx, "Is this correct") + helper.SendLine(ctx, "\n") + + helper.ExpectString(ctx, "Select container for which you want to change configuration") + helper.SendLine(ctx, "\n") + + helper.ExpectString(ctx, "Enter component name") + helper.SendLine(ctx, "my-app") + + helper.ExpectString(ctx, "Press Ctrl+c to exit") + ctx.StopCommand() + }) + + lines, err := helper.ExtractLines(output) + Expect(err).To(BeNil()) + Expect(lines).To(Not(BeEmpty())) + Expect(lines[0]).To(Equal("The current directory already contains source code. " + + "odo will try to autodetect the language and project type in order to select the best suited Devfile for your project.")) + }) }) })