Browse Source

update CLI help for porter create

Alexander Belanger 4 năm trước cách đây
mục cha
commit
b5b2ad4700
3 tập tin đã thay đổi với 210 bổ sung105 xóa
  1. 67 10
      cli/cmd/create.go
  2. 86 95
      cli/cmd/deploy.go
  3. 57 0
      cli/cmd/deploy/create.go

+ 67 - 10
cli/cmd/create.go

@@ -19,7 +19,48 @@ import (
 var createCmd = &cobra.Command{
 	Use:   "create [kind]",
 	Args:  cobra.ExactArgs(1),
-	Short: "TODO.",
+	Short: "Creates a new application with name given by the --app flag.",
+	Long: fmt.Sprintf(`
+%s 
+
+Creates a new application with name given by the --app flag and a "kind", which can be one of 
+web, worker, or job. For example:
+
+  %s
+
+To modify the default configuration of the application, you can pass a values.yaml file in via the 
+--values flag. 
+
+  %s
+
+To read more about the configuration options, go here: 
+
+https://docs.getporter.dev/docs/deploying-from-the-cli#common-configuration-options
+
+This command will automatically build from a local path, and will create a new Docker image in your 
+default Docker registry. The path can be configured via the --path flag. For example:
+  
+  %s
+
+To connect the application to Github, so that the application rebuilds and redeploys on each push 
+to a Github branch, you can specify "--source github". If your local branch is set to track changes 
+from an upstream remote branch, Porter will try to use the connected remote and remote branch as the 
+Github repository to link to. Otherwise, Porter will use the remote given by origin. For example:
+
+  %s
+
+To deploy an application from a Docker registry, use "--source registry" and pass the image in via the
+--image flag. The image flag must be of the form repository:tag. For example:
+
+  %s 
+`,
+		color.New(color.FgBlue, color.Bold).Sprintf("Help for \"porter create\":"),
+		color.New(color.FgGreen, color.Bold).Sprintf("porter create web --app example-app"),
+		color.New(color.FgGreen, color.Bold).Sprintf("porter create web --app example-app --values values.yaml"),
+		color.New(color.FgGreen, color.Bold).Sprintf("porter create web --app example-app --path ./path/to/app"),
+		color.New(color.FgGreen, color.Bold).Sprintf("porter create web --app example-app --source github"),
+		color.New(color.FgGreen, color.Bold).Sprintf("porter create web --app example-app --source registry --image gcr.io/snowflake-12345/example-app:latest"),
+	),
 	Run: func(cmd *cobra.Command, args []string) {
 		err := checkLoginAndRun(args, createFull)
 
@@ -32,24 +73,25 @@ var createCmd = &cobra.Command{
 var name string
 var values string
 var source string
+var image string
 
 func init() {
 	rootCmd.AddCommand(createCmd)
 
 	createCmd.PersistentFlags().StringVar(
 		&name,
-		"name",
+		"app",
 		"",
-		"Name of the new application/job/worker.",
+		"name of the new application/job/worker.",
 	)
 
-	createCmd.MarkPersistentFlagRequired("name")
+	createCmd.MarkPersistentFlagRequired("app")
 
 	createCmd.PersistentFlags().BoolVar(
 		&local,
 		"local",
 		true,
-		"Whether local context should be used for build",
+		"whether local context should be used for build",
 	)
 
 	createCmd.PersistentFlags().StringVarP(
@@ -57,14 +99,14 @@ func init() {
 		"path",
 		"p",
 		".",
-		"If local build, the path to the build directory",
+		"if local build, the path to the build directory",
 	)
 
 	createCmd.PersistentFlags().StringVar(
 		&namespace,
 		"namespace",
 		"default",
-		"Namespace of the application",
+		"namespace of the application",
 	)
 
 	createCmd.PersistentFlags().StringVarP(
@@ -72,7 +114,7 @@ func init() {
 		"values",
 		"v",
 		"",
-		"Filepath to a values.yaml file",
+		"filepath to a values.yaml file",
 	)
 
 	createCmd.PersistentFlags().StringVar(
@@ -93,7 +135,14 @@ func init() {
 		&source,
 		"source",
 		"local",
-		"the type of source (\"local\" or \"github\")",
+		"the type of source (\"local\", \"github\", or \"registry\")",
+	)
+
+	createCmd.PersistentFlags().StringVar(
+		&image,
+		"image",
+		"",
+		"if the source is \"registry\", the image to use, in image-path:tag format",
 	)
 }
 
@@ -152,8 +201,16 @@ func createFull(resp *api.AuthCheckResponse, client *api.Client, args []string)
 		}
 
 		color.New(color.FgGreen).Printf("Your web application is ready at: %s\n", subdomain)
-	} else {
+	} else if source == "github" {
 		return createFromGithub(createAgent, valuesObj)
+	} else {
+		subdomain, err := createAgent.CreateFromRegistry(image, valuesObj)
+
+		if err != nil {
+			return err
+		}
+
+		color.New(color.FgGreen).Printf("Your web application is ready at: %s\n", subdomain)
 	}
 
 	return nil

+ 86 - 95
cli/cmd/deploy.go

@@ -10,28 +10,31 @@ import (
 	"github.com/spf13/cobra"
 )
 
-// deployCmd represents the "porter deploy" base command when called
+// updateCmd represents the "porter update" base command when called
 // without any subcommands
-var deployCmd = &cobra.Command{
-	Use:   "deploy",
-	Short: "Builds and deploys a specified application given by the --app flag.",
+var updateCmd = &cobra.Command{
+	Use:   "update",
+	Short: "Builds and updates a specified application given by the --app flag.",
 	Long: fmt.Sprintf(`
 %s 
 
-Builds and deploys a specified application given by the --app flag. For example:
+Builds and updates a specified application given by the --app flag. For example:
 
   %s
 
-If the application has a remote Git repository source configured, this command uses the latest commit 
-from the remote repo and branch to deploy an application. It will use the latest commit as the image 
-tag. 
-
-To build from a local directory, you must specify the --local flag. The path can be configured via the 
+This command will automatically build from a local path. The path can be configured via the 
 --path flag. You can also overwrite the tag using the --tag flag. For example, to build from the 
 local directory ~/path-to-dir with the tag "testing":
 
   %s
 
+If the application has a remote Git repository source configured, you can specify that the remote
+Git repository should be used to build the new image by specifying "--local false". Porter will use 
+the latest commit from the remote repo and branch to update an application, and will use the latest 
+commit as the image tag.
+
+  %s
+
 To add new configuration or update existing configuration, you can pass a values.yaml file in via the 
 --values flag. For example;
 
@@ -44,28 +47,16 @@ in your remote Git repository. For example, if a Dockerfile is found at ./docker
 specify it as follows:
 
   %s
-
-If an application does not have a remote Git repository source, this command will attempt to use a 
-cloud-native buildpack builder and build from the current directory. If this is the desired behavior,
-you do not need to configure additional flags:
-
-  %s
-
-If you would like to build from a Dockerfile instead, use the flag --dockerfile and "--method docker"
-as documented above. For example:
-
-  %s
 `,
-		color.New(color.FgBlue, color.Bold).Sprintf("Help for \"porter deploy\":"),
-		color.New(color.FgGreen, color.Bold).Sprintf("porter deploy --app example-app"),
-		color.New(color.FgGreen, color.Bold).Sprintf("porter deploy --app remote-git-app --local --path ~/path-to-dir --tag testing"),
-		color.New(color.FgGreen, color.Bold).Sprintf("porter deploy --app remote-git-app --values my-values.yaml"),
-		color.New(color.FgGreen, color.Bold).Sprintf("porter deploy --app remote-git-app --method docker --dockerfile ./docker/prod.Dockerfile"),
-		color.New(color.FgGreen, color.Bold).Sprintf("porter deploy --app local-app"),
-		color.New(color.FgGreen, color.Bold).Sprintf("porter deploy --app local-app --method docker --dockerfile ~/porter-test/prod.Dockerfile"),
+		color.New(color.FgBlue, color.Bold).Sprintf("Help for \"porter update\":"),
+		color.New(color.FgGreen, color.Bold).Sprintf("porter update --app example-app"),
+		color.New(color.FgGreen, color.Bold).Sprintf("porter update --app example-app --path ~/path-to-dir --tag testing"),
+		color.New(color.FgGreen, color.Bold).Sprintf("porter update --app remote-git-app --local false"),
+		color.New(color.FgGreen, color.Bold).Sprintf("porter update --app example-app --values my-values.yaml"),
+		color.New(color.FgGreen, color.Bold).Sprintf("porter update --app example-app --method docker --dockerfile ./docker/prod.Dockerfile"),
 	),
 	Run: func(cmd *cobra.Command, args []string) {
-		err := checkLoginAndRun(args, deployFull)
+		err := checkLoginAndRun(args, updateFull)
 
 		if err != nil {
 			os.Exit(1)
@@ -73,7 +64,7 @@ as documented above. For example:
 	},
 }
 
-var deployGetEnvCmd = &cobra.Command{
+var updateGetEnvCmd = &cobra.Command{
 	Use:   "get-env",
 	Short: "Gets environment variables for a deployment for a specified application given by the --app flag.",
 	Long: fmt.Sprintf(`
@@ -89,12 +80,12 @@ destination path for a .env file. For example:
 
   %s
 `,
-		color.New(color.FgBlue, color.Bold).Sprintf("Help for \"porter deploy get-env\":"),
-		color.New(color.FgGreen, color.Bold).Sprintf("porter deploy get-env --app example-app | xargs"),
-		color.New(color.FgGreen, color.Bold).Sprintf("porter deploy get-env --app example-app --file .env"),
+		color.New(color.FgBlue, color.Bold).Sprintf("Help for \"porter update get-env\":"),
+		color.New(color.FgGreen, color.Bold).Sprintf("porter update get-env --app example-app | xargs"),
+		color.New(color.FgGreen, color.Bold).Sprintf("porter update get-env --app example-app --file .env"),
 	),
 	Run: func(cmd *cobra.Command, args []string) {
-		err := checkLoginAndRun(args, deployGetEnv)
+		err := checkLoginAndRun(args, updateGetEnv)
 
 		if err != nil {
 			os.Exit(1)
@@ -102,7 +93,7 @@ destination path for a .env file. For example:
 	},
 }
 
-var deployBuildCmd = &cobra.Command{
+var updateBuildCmd = &cobra.Command{
 	Use:   "build",
 	Short: "Builds a new version of the application specified by the --app flag.",
 	Long: fmt.Sprintf(`
@@ -131,13 +122,13 @@ for the application:
 
   %s
 `,
-		color.New(color.FgBlue, color.Bold).Sprintf("Help for \"porter deploy build\":"),
-		color.New(color.FgGreen, color.Bold).Sprintf("porter deploy build --app example-app"),
-		color.New(color.FgGreen, color.Bold).Sprintf("porter deploy build --app example-app --method docker"),
-		color.New(color.FgGreen, color.Bold).Sprintf("porter deploy build --app example-app --method docker --dockerfile ./prod.Dockerfile"),
+		color.New(color.FgBlue, color.Bold).Sprintf("Help for \"porter update build\":"),
+		color.New(color.FgGreen, color.Bold).Sprintf("porter update build --app example-app"),
+		color.New(color.FgGreen, color.Bold).Sprintf("porter update build --app example-app --method docker"),
+		color.New(color.FgGreen, color.Bold).Sprintf("porter update build --app example-app --method docker --dockerfile ./prod.Dockerfile"),
 	),
 	Run: func(cmd *cobra.Command, args []string) {
-		err := checkLoginAndRun(args, deployBuild)
+		err := checkLoginAndRun(args, updateBuild)
 
 		if err != nil {
 			os.Exit(1)
@@ -145,7 +136,7 @@ for the application:
 	},
 }
 
-var deployPushCmd = &cobra.Command{
+var updatePushCmd = &cobra.Command{
 	Use:   "push",
 	Short: "Pushes a new image for an application specified by the --app flag.",
 	Long: fmt.Sprintf(`
@@ -162,11 +153,11 @@ This command will not use your pre-saved authentication set up via "docker login
 are using an image registry that was created outside of Porter, make sure that you have 
 linked it via "porter connect".
 `,
-		color.New(color.FgBlue, color.Bold).Sprintf("Help for \"porter deploy push\":"),
-		color.New(color.FgGreen, color.Bold).Sprintf("porter deploy push --app nginx --tag new-tag"),
+		color.New(color.FgBlue, color.Bold).Sprintf("Help for \"porter update push\":"),
+		color.New(color.FgGreen, color.Bold).Sprintf("porter update push --app nginx --tag new-tag"),
 	),
 	Run: func(cmd *cobra.Command, args []string) {
-		err := checkLoginAndRun(args, deployPush)
+		err := checkLoginAndRun(args, updatePush)
 
 		if err != nil {
 			os.Exit(1)
@@ -174,8 +165,8 @@ linked it via "porter connect".
 	},
 }
 
-var deployCallWebhookCmd = &cobra.Command{
-	Use:   "update-config",
+var updateConfigCmd = &cobra.Command{
+	Use:   "config",
 	Short: "Updates the configuration for an application specified by the --app flag.",
 	Long: fmt.Sprintf(`
 %s 
@@ -192,12 +183,12 @@ the image that the application uses if no --values file is specified:
 
   %s
 `,
-		color.New(color.FgBlue, color.Bold).Sprintf("Help for \"porter deploy update-config\":"),
-		color.New(color.FgGreen, color.Bold).Sprintf("porter deploy call-webhook --app example-app --values my-values.yaml"),
-		color.New(color.FgGreen, color.Bold).Sprintf("porter deploy call-webhook --app example-app --tag custom-tag"),
+		color.New(color.FgBlue, color.Bold).Sprintf("Help for \"porter update update-config\":"),
+		color.New(color.FgGreen, color.Bold).Sprintf("porter update call-webhook --app example-app --values my-values.yaml"),
+		color.New(color.FgGreen, color.Bold).Sprintf("porter update call-webhook --app example-app --tag custom-tag"),
 	),
 	Run: func(cmd *cobra.Command, args []string) {
-		err := checkLoginAndRun(args, deployUpgrade)
+		err := checkLoginAndRun(args, updateUpgrade)
 
 		if err != nil {
 			os.Exit(1)
@@ -214,32 +205,32 @@ var dockerfile string
 var method string
 
 func init() {
-	rootCmd.AddCommand(deployCmd)
+	rootCmd.AddCommand(updateCmd)
 
-	deployCmd.PersistentFlags().StringVar(
+	updateCmd.PersistentFlags().StringVar(
 		&app,
 		"app",
 		"",
 		"Application in the Porter dashboard",
 	)
 
-	deployCmd.MarkPersistentFlagRequired("app")
+	updateCmd.MarkPersistentFlagRequired("app")
 
-	deployCmd.PersistentFlags().StringVar(
+	updateCmd.PersistentFlags().StringVar(
 		&namespace,
 		"namespace",
 		"default",
 		"Namespace of the application",
 	)
 
-	deployCmd.PersistentFlags().BoolVar(
+	updateCmd.PersistentFlags().BoolVar(
 		&local,
 		"local",
 		true,
 		"Whether local context should be used for build",
 	)
 
-	deployCmd.PersistentFlags().StringVarP(
+	updateCmd.PersistentFlags().StringVarP(
 		&localPath,
 		"path",
 		"p",
@@ -247,7 +238,7 @@ func init() {
 		"If local build, the path to the build directory",
 	)
 
-	deployCmd.PersistentFlags().StringVarP(
+	updateCmd.PersistentFlags().StringVarP(
 		&tag,
 		"tag",
 		"t",
@@ -255,7 +246,7 @@ func init() {
 		"the specified tag to use, if not \"latest\"",
 	)
 
-	deployCmd.PersistentFlags().StringVarP(
+	updateCmd.PersistentFlags().StringVarP(
 		&values,
 		"values",
 		"v",
@@ -263,56 +254,56 @@ func init() {
 		"Filepath to a values.yaml file",
 	)
 
-	deployCmd.PersistentFlags().StringVar(
+	updateCmd.PersistentFlags().StringVar(
 		&dockerfile,
 		"dockerfile",
 		"",
 		"the path to the dockerfile",
 	)
 
-	deployCmd.PersistentFlags().StringVar(
+	updateCmd.PersistentFlags().StringVar(
 		&method,
 		"method",
 		"",
 		"the build method to use (\"docker\" or \"pack\")",
 	)
 
-	deployCmd.AddCommand(deployGetEnvCmd)
+	updateCmd.AddCommand(updateGetEnvCmd)
 
-	deployGetEnvCmd.PersistentFlags().StringVar(
+	updateGetEnvCmd.PersistentFlags().StringVar(
 		&getEnvFileDest,
 		"file",
 		"",
 		"file destination for .env files",
 	)
 
-	deployCmd.AddCommand(deployBuildCmd)
-	deployCmd.AddCommand(deployPushCmd)
-	deployCmd.AddCommand(deployCallWebhookCmd)
+	updateCmd.AddCommand(updateBuildCmd)
+	updateCmd.AddCommand(updatePushCmd)
+	updateCmd.AddCommand(updateConfigCmd)
 }
 
-func deployFull(resp *api.AuthCheckResponse, client *api.Client, args []string) error {
+func updateFull(resp *api.AuthCheckResponse, client *api.Client, args []string) error {
 	color.New(color.FgGreen).Println("Deploying app:", app)
 
-	deployAgent, err := deployGetAgent(client)
+	updateAgent, err := updateGetAgent(client)
 
 	if err != nil {
 		return err
 	}
 
-	err = deployBuildWithAgent(deployAgent)
+	err = updateBuildWithAgent(updateAgent)
 
 	if err != nil {
 		return err
 	}
 
-	err = deployPushWithAgent(deployAgent)
+	err = updatePushWithAgent(updateAgent)
 
 	if err != nil {
 		return err
 	}
 
-	err = deployUpgradeWithAgent(deployAgent)
+	err = updateUpgradeWithAgent(updateAgent)
 
 	if err != nil {
 		return err
@@ -321,69 +312,69 @@ func deployFull(resp *api.AuthCheckResponse, client *api.Client, args []string)
 	return nil
 }
 
-func deployGetEnv(resp *api.AuthCheckResponse, client *api.Client, args []string) error {
-	deployAgent, err := deployGetAgent(client)
+func updateGetEnv(resp *api.AuthCheckResponse, client *api.Client, args []string) error {
+	updateAgent, err := updateGetAgent(client)
 
 	if err != nil {
 		return err
 	}
 
-	buildEnv, err := deployAgent.GetBuildEnv()
+	buildEnv, err := updateAgent.GetBuildEnv()
 
 	if err != nil {
 		return err
 	}
 
 	// set the environment variables in the process
-	err = deployAgent.SetBuildEnv(buildEnv)
+	err = updateAgent.SetBuildEnv(buildEnv)
 
 	if err != nil {
 		return err
 	}
 
 	// write the environment variables to either a file or stdout (stdout by default)
-	return deployAgent.WriteBuildEnv(getEnvFileDest)
+	return updateAgent.WriteBuildEnv(getEnvFileDest)
 }
 
-func deployBuild(resp *api.AuthCheckResponse, client *api.Client, args []string) error {
-	deployAgent, err := deployGetAgent(client)
+func updateBuild(resp *api.AuthCheckResponse, client *api.Client, args []string) error {
+	updateAgent, err := updateGetAgent(client)
 
 	if err != nil {
 		return err
 	}
 
-	return deployBuildWithAgent(deployAgent)
+	return updateBuildWithAgent(updateAgent)
 }
 
-func deployPush(resp *api.AuthCheckResponse, client *api.Client, args []string) error {
-	deployAgent, err := deployGetAgent(client)
+func updatePush(resp *api.AuthCheckResponse, client *api.Client, args []string) error {
+	updateAgent, err := updateGetAgent(client)
 
 	if err != nil {
 		return err
 	}
 
-	return deployPushWithAgent(deployAgent)
+	return updatePushWithAgent(updateAgent)
 }
 
-func deployUpgrade(resp *api.AuthCheckResponse, client *api.Client, args []string) error {
-	deployAgent, err := deployGetAgent(client)
+func updateUpgrade(resp *api.AuthCheckResponse, client *api.Client, args []string) error {
+	updateAgent, err := updateGetAgent(client)
 
 	if err != nil {
 		return err
 	}
 
-	return deployUpgradeWithAgent(deployAgent)
+	return updateUpgradeWithAgent(updateAgent)
 }
 
 // HELPER METHODS
-func deployGetAgent(client *api.Client) (*deploy.DeployAgent, error) {
+func updateGetAgent(client *api.Client) (*deploy.DeployAgent, error) {
 	var buildMethod deploy.DeployBuildType
 
 	if method != "" {
 		buildMethod = deploy.DeployBuildType(method)
 	}
 
-	// initialize the deploy agent
+	// initialize the update agent
 	return deploy.NewDeployAgent(client, app, &deploy.DeployOpts{
 		SharedOpts: &deploy.SharedOpts{
 			ProjectID:       config.Project,
@@ -398,34 +389,34 @@ func deployGetAgent(client *api.Client) (*deploy.DeployAgent, error) {
 	})
 }
 
-func deployBuildWithAgent(deployAgent *deploy.DeployAgent) error {
+func updateBuildWithAgent(updateAgent *deploy.DeployAgent) error {
 	// build the deployment
 	color.New(color.FgGreen).Println("Building docker image for", app)
 
-	buildEnv, err := deployAgent.GetBuildEnv()
+	buildEnv, err := updateAgent.GetBuildEnv()
 
 	if err != nil {
 		return err
 	}
 
 	// set the environment variables in the process
-	err = deployAgent.SetBuildEnv(buildEnv)
+	err = updateAgent.SetBuildEnv(buildEnv)
 
 	if err != nil {
 		return err
 	}
 
-	return deployAgent.Build()
+	return updateAgent.Build()
 }
 
-func deployPushWithAgent(deployAgent *deploy.DeployAgent) error {
+func updatePushWithAgent(updateAgent *deploy.DeployAgent) error {
 	// push the deployment
 	color.New(color.FgGreen).Println("Pushing new image for", app)
 
-	return deployAgent.Push()
+	return updateAgent.Push()
 }
 
-func deployUpgradeWithAgent(deployAgent *deploy.DeployAgent) error {
+func updateUpgradeWithAgent(updateAgent *deploy.DeployAgent) error {
 	// push the deployment
 	color.New(color.FgGreen).Println("Calling webhook for", app)
 
@@ -436,13 +427,13 @@ func deployUpgradeWithAgent(deployAgent *deploy.DeployAgent) error {
 		return err
 	}
 
-	err = deployAgent.UpdateImageAndValues(valuesObj)
+	err = updateAgent.UpdateImageAndValues(valuesObj)
 
 	if err != nil {
 		return err
 	}
 
-	color.New(color.FgGreen).Println("Successfully re-deployed", app)
+	color.New(color.FgGreen).Println("Successfully re-updateed", app)
 
 	return nil
 }

+ 57 - 0
cli/cmd/deploy/create.go

@@ -5,6 +5,7 @@ import (
 	"fmt"
 	"os"
 	"path/filepath"
+	"strings"
 
 	"github.com/porter-dev/porter/cli/cmd/api"
 	"github.com/porter-dev/porter/cli/cmd/docker"
@@ -143,6 +144,62 @@ func (c *CreateAgent) CreateFromGithub(
 	return subdomain, nil
 }
 
+func (c *CreateAgent) CreateFromRegistry(
+	image string,
+	overrideValues map[string]interface{},
+) (string, error) {
+	if image == "" {
+		return "", fmt.Errorf("image cannot be empty")
+	}
+
+	// split image into image-path:tag format
+	imageSpl := strings.Split(image, ":")
+
+	if len(imageSpl) != 2 {
+		return "", fmt.Errorf("invalid image format: must be image-path:tag format")
+	}
+
+	opts := c.CreateOpts
+
+	latestVersion, mergedValues, err := c.getMergedValues(overrideValues)
+
+	if err != nil {
+		return "", err
+	}
+
+	mergedValues["image"] = map[string]interface{}{
+		"repository": imageSpl[0],
+		"tag":        imageSpl[1],
+	}
+
+	subdomain, err := c.CreateSubdomainIfRequired(mergedValues)
+
+	if err != nil {
+		return "", err
+	}
+
+	err = c.Client.DeployTemplate(
+		context.Background(),
+		opts.ProjectID,
+		opts.ClusterID,
+		opts.Kind,
+		latestVersion,
+		&api.DeployTemplateRequest{
+			TemplateName: opts.Kind,
+			ImageURL:     imageSpl[0],
+			FormValues:   mergedValues,
+			Namespace:    opts.Namespace,
+			Name:         opts.ReleaseName,
+		},
+	)
+
+	if err != nil {
+		return "", err
+	}
+
+	return subdomain, nil
+}
+
 func (c *CreateAgent) CreateFromDocker(
 	overrideValues map[string]interface{},
 ) (string, error) {