From 78358746ae481681caa9c9c929e959b17e78c5ec Mon Sep 17 00:00:00 2001 From: Kamran Shamsi Date: Wed, 29 Apr 2020 11:59:36 +0100 Subject: [PATCH 1/5] Allow a project to be specified in --downloadSource --- pkg/odo/cli/component/create.go | 45 +++++++++++++++---- pkg/odo/cli/component/ui/ui.go | 11 +++++ .../devfile/cmd_devfile_create_test.go | 23 ++++++++++ 3 files changed, 71 insertions(+), 8 deletions(-) diff --git a/pkg/odo/cli/component/create.go b/pkg/odo/cli/component/create.go index 4893fb3659f..fd55f2e6bb5 100644 --- a/pkg/odo/cli/component/create.go +++ b/pkg/odo/cli/component/create.go @@ -15,6 +15,7 @@ import ( "github.com/openshift/odo/pkg/component" "github.com/openshift/odo/pkg/config" "github.com/openshift/odo/pkg/devfile" + "github.com/openshift/odo/pkg/devfile/parser/data/common" "github.com/openshift/odo/pkg/envinfo" "github.com/openshift/odo/pkg/kclient" "github.com/openshift/odo/pkg/log" @@ -64,7 +65,7 @@ type DevfileMetadata struct { devfileSupport bool devfileLink string devfileRegistry string - downloadSource bool + downloadSource string } // CreateRecommendedCommandName is the recommended watch command name @@ -695,7 +696,8 @@ func (co *CreateOptions) Validate() (err error) { // Downloads first project from list of projects in devfile // Currenty type git with a non github url is not supported -func (co *CreateOptions) downloadProject() error { +func (co *CreateOptions) downloadProject(projectPassed string) error { + var project common.DevfileProject devObj, err := devfile.Parse(DevfilePath) if err != nil { return err @@ -706,11 +708,37 @@ func (co *CreateOptions) downloadProject() error { return errors.Errorf("No project found in devfile component.") } - if nOfProjects > 1 { - log.Warning("Only downloading first project from list.") + if nOfProjects > 1 && projectPassed == "no-project-passed-to-flag" { + co.interactive = true } - project := projects[0] + if nOfProjects == 1 && projectPassed == "no-project-passed-to-flag" { + project = projects[0] + } else if co.interactive && projectPassed == "no-project-passed-to-flag" { //If there is more than one project and the user hasn't specified which one to download. + var projectNames []string + for _, projectInfo := range projects { + projectNames = append(projectNames, projectInfo.Name) //Add all names to an array and use this as a survey + } + projectSelected := ui.SelectDevfileProject(projectNames) + + for indexOfProject, x := range projects { //We then need to find the index of the project selected + if x.Name == projectSelected { + project = projects[indexOfProject] + } + } + } else { //If the user has specified a project + projectFound := false + for indexOfProject, projectInfo := range projects { + if projectInfo.Name == projectPassed { //Get the index + project = projects[indexOfProject] + projectFound = true + } + } + + if !projectFound { + return errors.Errorf("The project: %s specified in --downloadSource does not exist", projectPassed) + } + } path, err := os.Getwd() if err != nil { @@ -779,8 +807,8 @@ func (co *CreateOptions) Run() (err error) { } } - if util.CheckPathExists(DevfilePath) && co.devfileMetadata.downloadSource { - err = co.downloadProject() + if util.CheckPathExists(DevfilePath) && co.devfileMetadata.downloadSource != "" { + err = co.downloadProject(co.devfileMetadata.downloadSource) if err != nil { return errors.Wrap(err, "Failed to download project for devfile component") } @@ -900,7 +928,8 @@ func NewCmdCreate(name, fullName string) *cobra.Command { if experimental.IsExperimentalModeEnabled() { componentCreateCmd.Flags().StringVarP(&co.devfileMetadata.componentNamespace, "namespace", "n", "", "Create devfile component under specific namespace") - componentCreateCmd.Flags().BoolVar(&co.devfileMetadata.downloadSource, "downloadSource", false, "Download sample project from devfile. (ex. odo component create [component_name] --downloadSource") + componentCreateCmd.Flags().StringVar(&co.devfileMetadata.downloadSource, "downloadSource", "", "Download sample project from devfile. (ex. odo component create [component_name] --downloadSource") + componentCreateCmd.Flags().Lookup("downloadSource").NoOptDefVal = "no-project-passed-to-flag" //Default value to pass to the flag if one is not specified. } componentCreateCmd.SetUsageTemplate(odoutil.CmdUsageTemplate) diff --git a/pkg/odo/cli/component/ui/ui.go b/pkg/odo/cli/component/ui/ui.go index d29c30c0bbf..2affa008de7 100644 --- a/pkg/odo/cli/component/ui/ui.go +++ b/pkg/odo/cli/component/ui/ui.go @@ -28,6 +28,17 @@ func SelectDevfileComponentType(options []catalog.DevfileComponentType) string { return componentType } +func SelectDevfileProject(options []string) string { + var projectName string + prompt := &survey.Select{ + Message: "Which project do you wish to download?", + Options: options, + } + err := survey.AskOne(prompt, &projectName, survey.Required) + ui.HandleError(err) + return projectName +} + // EnterDevfileComponentName lets the user to specify the component name in the prompt func EnterDevfileComponentName(defaultComponentName string) string { var componentName string diff --git a/tests/integration/devfile/cmd_devfile_create_test.go b/tests/integration/devfile/cmd_devfile_create_test.go index e332ddbe933..48d038f074c 100644 --- a/tests/integration/devfile/cmd_devfile_create_test.go +++ b/tests/integration/devfile/cmd_devfile_create_test.go @@ -149,6 +149,29 @@ var _ = Describe("odo devfile create command tests", func() { }) }) + Context("When executing odo create with devfile component and --downloadSource flag with a valid project", func() { + It("should succesfully create the compoment specified and download the source", func() { + helper.CmdShouldPass("odo", "preference", "set", "Experimental", "true") + contextDevfile := helper.CreateNewContext() + helper.Chdir(contextDevfile) + devfile := "devfile.yaml" + helper.CmdShouldPass("odo", "create", "nodejs", "--downloadSource=nodejs-web-app") + expectedFiles := []string{"package.json", "package-lock.json", "README.md", devfile} + Expect(helper.VerifyFilesExist(contextDevfile, expectedFiles)).To(Equal(true)) + helper.DeleteDir(contextDevfile) + helper.Chdir(context) + }) + }) + + Context("When executing odo create with an invalid project specified in --downloadSource", func() { + It("should fail with please run 'The project: invalid-project-name specified in --downloadSource does not exist'", func() { + invalidProjectName := "invalid-project-name" + output := helper.CmdShouldFail("odo", "create", "nodejs", "--downloadSource=invalid-project-name") + expectedString := "The project: " + invalidProjectName + " specified in --downloadSource does not exist" + helper.MatchAllInOutput(output, []string{expectedString}) + }) + }) + // Currently these tests need interactive mode in order to set the name of the component. // Once this feature is added we can change these tests. //Context("When executing odo create with devfile component and --downloadSource flag with github type", func() { From bc7dc1b787b94c816e7ff8feb33110e3c3d44e9f Mon Sep 17 00:00:00 2001 From: Kamran Shamsi Date: Wed, 29 Apr 2020 15:18:57 +0100 Subject: [PATCH 2/5] Added test for devfile with no projects --- tests/integration/devfile/cmd_devfile_create_test.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/integration/devfile/cmd_devfile_create_test.go b/tests/integration/devfile/cmd_devfile_create_test.go index 9acca9c32c9..e78dae74bc2 100644 --- a/tests/integration/devfile/cmd_devfile_create_test.go +++ b/tests/integration/devfile/cmd_devfile_create_test.go @@ -165,6 +165,14 @@ var _ = Describe("odo devfile create command tests", func() { }) }) + Context("When executing odo create using --downloadSource with a devfile component that contains no projects", func() { + It("should fail with please run 'No project found in devfile component.'", func() { + output := helper.CmdShouldFail("odo", "create", "maven", "--downloadSource") + expectedString := "No project found in devfile component." + helper.MatchAllInOutput(output, []string{expectedString}) + }) + }) + // Currently these tests need interactive mode in order to set the name of the component. // Once this feature is added we can change these tests. //Context("When executing odo create with devfile component and --downloadSource flag with github type", func() { From 4b162396dd032edd22b190c14d19312272b4448f Mon Sep 17 00:00:00 2001 From: Kamran Shamsi Date: Thu, 30 Apr 2020 15:11:23 +0100 Subject: [PATCH 3/5] Remove interactive mode feature. --- pkg/odo/cli/component/create.go | 21 ++++----------------- pkg/odo/cli/component/ui/ui.go | 11 ----------- 2 files changed, 4 insertions(+), 28 deletions(-) diff --git a/pkg/odo/cli/component/create.go b/pkg/odo/cli/component/create.go index b35093d3214..7d7aadc8ba3 100644 --- a/pkg/odo/cli/component/create.go +++ b/pkg/odo/cli/component/create.go @@ -708,24 +708,11 @@ func (co *CreateOptions) downloadProject(projectPassed string) error { return errors.Errorf("No project found in devfile component.") } - if nOfProjects > 1 && projectPassed == "no-project-passed-to-flag" { - co.interactive = true - } - if nOfProjects == 1 && projectPassed == "no-project-passed-to-flag" { project = projects[0] - } else if co.interactive && projectPassed == "no-project-passed-to-flag" { //If there is more than one project and the user hasn't specified which one to download. - var projectNames []string - for _, projectInfo := range projects { - projectNames = append(projectNames, projectInfo.Name) //Add all names to an array and use this as a survey - } - projectSelected := ui.SelectDevfileProject(projectNames) - - for indexOfProject, x := range projects { //We then need to find the index of the project selected - if x.Name == projectSelected { - project = projects[indexOfProject] - } - } + } else if nOfProjects > 1 && projectPassed == "no-project-passed-to-flag" { + project = projects[0] + log.Warning("There are multiple projects in this devfile but none have been specified in --downloadSource. Downloading the first.") } else { //If the user has specified a project projectFound := false for indexOfProject, projectInfo := range projects { @@ -927,7 +914,7 @@ func NewCmdCreate(name, fullName string) *cobra.Command { componentCreateCmd.Flags().StringSliceVar(&co.componentEnvVars, "env", []string{}, "Environmental variables for the component. For example --env VariableName=Value") if experimental.IsExperimentalModeEnabled() { - componentCreateCmd.Flags().StringVar(&co.devfileMetadata.downloadSource, "downloadSource", "", "Download sample project from devfile. (ex. odo component create [component_name] --downloadSource") + componentCreateCmd.Flags().StringVar(&co.devfileMetadata.downloadSource, "downloadSource", "", "Download sample project from devfile. (ex. odo component create [component_name] --downloadSource/--downloadSource=") componentCreateCmd.Flags().Lookup("downloadSource").NoOptDefVal = "no-project-passed-to-flag" //Default value to pass to the flag if one is not specified. } diff --git a/pkg/odo/cli/component/ui/ui.go b/pkg/odo/cli/component/ui/ui.go index 2affa008de7..d29c30c0bbf 100644 --- a/pkg/odo/cli/component/ui/ui.go +++ b/pkg/odo/cli/component/ui/ui.go @@ -28,17 +28,6 @@ func SelectDevfileComponentType(options []catalog.DevfileComponentType) string { return componentType } -func SelectDevfileProject(options []string) string { - var projectName string - prompt := &survey.Select{ - Message: "Which project do you wish to download?", - Options: options, - } - err := survey.AskOne(prompt, &projectName, survey.Required) - ui.HandleError(err) - return projectName -} - // EnterDevfileComponentName lets the user to specify the component name in the prompt func EnterDevfileComponentName(defaultComponentName string) string { var componentName string From ba8f12df0232a6f12b4206c5211651935af838ad Mon Sep 17 00:00:00 2001 From: Kamran Shamsi Date: Mon, 4 May 2020 10:38:12 +0100 Subject: [PATCH 4/5] Added project name to warning, altered default name --- pkg/odo/cli/component/create.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/odo/cli/component/create.go b/pkg/odo/cli/component/create.go index 7d7aadc8ba3..1f54d94b53b 100644 --- a/pkg/odo/cli/component/create.go +++ b/pkg/odo/cli/component/create.go @@ -708,11 +708,11 @@ func (co *CreateOptions) downloadProject(projectPassed string) error { return errors.Errorf("No project found in devfile component.") } - if nOfProjects == 1 && projectPassed == "no-project-passed-to-flag" { + if nOfProjects == 1 && projectPassed == "devfile-project-name" { project = projects[0] - } else if nOfProjects > 1 && projectPassed == "no-project-passed-to-flag" { + } else if nOfProjects > 1 && projectPassed == "devfile-project-name" { project = projects[0] - log.Warning("There are multiple projects in this devfile but none have been specified in --downloadSource. Downloading the first.") + log.Warning("There are multiple projects in this devfile but none have been specified in --downloadSource. Downloading the first: " + project.Name) } else { //If the user has specified a project projectFound := false for indexOfProject, projectInfo := range projects { @@ -915,7 +915,7 @@ func NewCmdCreate(name, fullName string) *cobra.Command { if experimental.IsExperimentalModeEnabled() { componentCreateCmd.Flags().StringVar(&co.devfileMetadata.downloadSource, "downloadSource", "", "Download sample project from devfile. (ex. odo component create [component_name] --downloadSource/--downloadSource=") - componentCreateCmd.Flags().Lookup("downloadSource").NoOptDefVal = "no-project-passed-to-flag" //Default value to pass to the flag if one is not specified. + componentCreateCmd.Flags().Lookup("downloadSource").NoOptDefVal = "devfile-project-name" //Default value to pass to the flag if one is not specified. } componentCreateCmd.SetUsageTemplate(odoutil.CmdUsageTemplate) From 55022397ea400c5a845cd0014949136ce44a0b8a Mon Sep 17 00:00:00 2001 From: Kamran Shamsi Date: Thu, 7 May 2020 20:52:29 +0100 Subject: [PATCH 5/5] Address comments --- pkg/odo/cli/component/create.go | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/pkg/odo/cli/component/create.go b/pkg/odo/cli/component/create.go index 1f54d94b53b..210de61865b 100644 --- a/pkg/odo/cli/component/create.go +++ b/pkg/odo/cli/component/create.go @@ -110,7 +110,12 @@ var createExample = ktemplates.Examples(` # Create new Node.js component with t %[1]s nodejs --git https://github.com/openshift/nodejs-ex.git # Create new Node.js component with custom ports, additional environment variables and memory and cpu limits -%[1]s nodejs --port 8080,8100/tcp,9100/udp --env key=value,key1=value1 --memory 4Gi --cpu 2`) +%[1]s nodejs --port 8080,8100/tcp,9100/udp --env key=value,key1=value1 --memory 4Gi --cpu 2 + +# Create new Node.js component and download the sample project named nodejs-web-app +%[1]s nodejs --downloadSource=nodejs-web-app`) + +const defaultProjectName = "devfile-project-name" // NewCreateOptions returns new instance of CreateOptions func NewCreateOptions() *CreateOptions { @@ -708,9 +713,9 @@ func (co *CreateOptions) downloadProject(projectPassed string) error { return errors.Errorf("No project found in devfile component.") } - if nOfProjects == 1 && projectPassed == "devfile-project-name" { + if nOfProjects == 1 && projectPassed == defaultProjectName { project = projects[0] - } else if nOfProjects > 1 && projectPassed == "devfile-project-name" { + } else if nOfProjects > 1 && projectPassed == defaultProjectName { project = projects[0] log.Warning("There are multiple projects in this devfile but none have been specified in --downloadSource. Downloading the first: " + project.Name) } else { //If the user has specified a project @@ -914,8 +919,8 @@ func NewCmdCreate(name, fullName string) *cobra.Command { componentCreateCmd.Flags().StringSliceVar(&co.componentEnvVars, "env", []string{}, "Environmental variables for the component. For example --env VariableName=Value") if experimental.IsExperimentalModeEnabled() { - componentCreateCmd.Flags().StringVar(&co.devfileMetadata.downloadSource, "downloadSource", "", "Download sample project from devfile. (ex. odo component create [component_name] --downloadSource/--downloadSource=") - componentCreateCmd.Flags().Lookup("downloadSource").NoOptDefVal = "devfile-project-name" //Default value to pass to the flag if one is not specified. + componentCreateCmd.Flags().StringVar(&co.devfileMetadata.downloadSource, "downloadSource", "", "Download sample project from devfile.") + componentCreateCmd.Flags().Lookup("downloadSource").NoOptDefVal = defaultProjectName //Default value to pass to the flag if one is not specified. } componentCreateCmd.SetUsageTemplate(odoutil.CmdUsageTemplate)